<!DOCTYPE HTML>
<html lang="zh-CN">


<head>
    <meta charset="utf-8">
    <meta name="keywords" content="Java正则, 先谢郭嘉&#39;blog">
    <meta name="description" content="Java 正则从入门到精通
关键词：Pattern、Matcher、捕获与非捕获、反向引用、零宽断言、贪婪与懒惰、元字符、DFA、NFA

正则简介正则表达式是什么正则表达式（Regular Expression）是一个用正则符号写出的公式">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="renderer" content="webkit|ie-stand|ie-comp">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="format-detection" content="telephone=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <meta name="referrer" content="no-referrer-when-downgrade">
    <!-- Global site tag (gtag.js) - Google Analytics -->


    <title>Java正则 | 先谢郭嘉&#39;blog</title>
    <link rel="icon" type="image/png" href="/blog/favicon.png">

    <link rel="stylesheet" type="text/css" href="/blog/libs/awesome/css/all.min.css">
    <link rel="stylesheet" type="text/css" href="/blog/libs/materialize/materialize.min.css">
    <link rel="stylesheet" type="text/css" href="/blog/libs/aos/aos.css">
    <link rel="stylesheet" type="text/css" href="/blog/libs/animate/animate.min.css">
    <link rel="stylesheet" type="text/css" href="/blog/libs/lightGallery/css/lightgallery.min.css">
    <link rel="stylesheet" type="text/css" href="/blog/css/matery.css">
    <link rel="stylesheet" type="text/css" href="/blog/css/my.css">

    <script src="/blog/libs/jquery/jquery-3.6.0.min.js"></script>

<meta name="generator" content="Hexo 6.0.0">
<style>.github-emoji { position: relative; display: inline-block; width: 1.2em; min-height: 1.2em; overflow: hidden; vertical-align: top; color: transparent; }  .github-emoji > span { position: relative; z-index: 10; }  .github-emoji img, .github-emoji .fancybox { margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; text-decoration: none !important; user-select: none !important; cursor: auto !important; }  .github-emoji img { height: 1.2em !important; width: 1.2em !important; position: absolute !important; left: 50% !important; top: 50% !important; transform: translate(-50%, -50%) !important; user-select: none !important; cursor: auto !important; } .github-emoji-fallback { color: inherit; } .github-emoji-fallback img { opacity: 0 !important; }</style>
<link rel="alternate" href="/blog/atom.xml" title="先谢郭嘉'blog" type="application/atom+xml">
</head>




<body>
    <header class="navbar-fixed">
    <nav id="headNav" class="bg-color nav-transparent">
        <div id="navContainer" class="nav-wrapper container">
            <div class="brand-logo">
                <a href="/blog/" class="waves-effect waves-light">
                    
                    <img src="/blog/medias/logo.png" class="logo-img" alt="LOGO">
                    
                    <span class="logo-span">先谢郭嘉&#39;blog</span>
                </a>
            </div>
            

<a href="#" data-target="mobile-nav" class="sidenav-trigger button-collapse"><i class="fas fa-bars"></i></a>
<ul class="right nav-menu">
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/blog/" class="waves-effect waves-light">
      
      <i class="fas fa-home" style="zoom: 0.6;"></i>
      
      <span>首页</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/blog/tags" class="waves-effect waves-light">
      
      <i class="fas fa-tags" style="zoom: 0.6;"></i>
      
      <span>标签</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/blog/categories" class="waves-effect waves-light">
      
      <i class="fas fa-bookmark" style="zoom: 0.6;"></i>
      
      <span>分类</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/blog/archive" class="waves-effect waves-light">
      
      <i class="fas fa-archive" style="zoom: 0.6;"></i>
      
      <span>归档</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/blog/about" class="waves-effect waves-light">
      
      <i class="fas fa-user-circle" style="zoom: 0.6;"></i>
      
      <span>关于</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/blog/contact" class="waves-effect waves-light">
      
      <i class="fas fa-comments" style="zoom: 0.6;"></i>
      
      <span>留言板</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/blog/friends" class="waves-effect waves-light">
      
      <i class="fas fa-address-book" style="zoom: 0.6;"></i>
      
      <span>友情链接</span>
    </a>
    
  </li>
  
  <li>
    <a href="#searchModal" class="modal-trigger waves-effect waves-light">
      <i id="searchIcon" class="fas fa-search" title="搜索" style="zoom: 0.85;"></i>
    </a>
  </li>
</ul>


<div id="mobile-nav" class="side-nav sidenav">

    <div class="mobile-head bg-color">
        
        <img src="/blog/medias/logo.png" class="logo-img circle responsive-img">
        
        <div class="logo-name">先谢郭嘉&#39;blog</div>
        <div class="logo-desc">
            
            Never really desperate, only the lost of the soul.
            
        </div>
    </div>

    <ul class="menu-list mobile-menu-list">
        
        <li class="m-nav-item">
	  
		<a href="/blog/" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-home"></i>
			
			首页
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/blog/tags" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-tags"></i>
			
			标签
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/blog/categories" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-bookmark"></i>
			
			分类
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/blog/archive" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-archive"></i>
			
			归档
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/blog/about" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-user-circle"></i>
			
			关于
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/blog/contact" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-comments"></i>
			
			留言板
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/blog/friends" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-address-book"></i>
			
			友情链接
		</a>
          
        </li>
        
        
        <li><div class="divider"></div></li>
        <li>
            <a href="https://github.com/xiejiabin1/xiejiabin1.github.io" class="waves-effect waves-light" target="_blank">
                <i class="fab fa-github-square fa-fw"></i>Fork Me
            </a>
        </li>
        
    </ul>
</div>


        </div>

        
            <style>
    .nav-transparent .github-corner {
        display: none !important;
    }

    .github-corner {
        position: absolute;
        z-index: 10;
        top: 0;
        right: 0;
        border: 0;
        transform: scale(1.1);
    }

    .github-corner svg {
        color: #0f9d58;
        fill: #fff;
        height: 64px;
        width: 64px;
    }

    .github-corner:hover .octo-arm {
        animation: a 0.56s ease-in-out;
    }

    .github-corner .octo-arm {
        animation: none;
    }

    @keyframes a {
        0%,
        to {
            transform: rotate(0);
        }
        20%,
        60% {
            transform: rotate(-25deg);
        }
        40%,
        80% {
            transform: rotate(10deg);
        }
    }
</style>

<a href="https://github.com/xiejiabin1/xiejiabin1.github.io" class="github-corner tooltipped hide-on-med-and-down" target="_blank"
   data-tooltip="Fork Me" data-position="left" data-delay="50">
    <svg viewBox="0 0 250 250" aria-hidden="true">
        <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
        <path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
              fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
        <path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
              fill="currentColor" class="octo-body"></path>
    </svg>
</a>
        
    </nav>

</header>

    



<div class="bg-cover pd-header post-cover" style="background-image: url('/blog/images/01-Java/01-JavaSE/background.jpg')">
    <div class="container" style="right: 0px;left: 0px;">
        <div class="row">
            <div class="col s12 m12 l12">
                <div class="brand">
                    <h1 class="description center-align post-title">Java正则</h1>
                </div>
            </div>
        </div>
    </div>
</div>




<main class="post-container content">

    
    <link rel="stylesheet" href="/blog/libs/tocbot/tocbot.css">
<style>
    #articleContent h1::before,
    #articleContent h2::before,
    #articleContent h3::before,
    #articleContent h4::before,
    #articleContent h5::before,
    #articleContent h6::before {
        display: block;
        content: " ";
        height: 100px;
        margin-top: -100px;
        visibility: hidden;
    }

    #articleContent :focus {
        outline: none;
    }

    .toc-fixed {
        position: fixed;
        top: 64px;
    }

    .toc-widget {
        width: 345px;
        padding-left: 20px;
    }

    .toc-widget .toc-title {
        padding: 35px 0 15px 17px;
        font-size: 1.5rem;
        font-weight: bold;
        line-height: 1.5rem;
    }

    .toc-widget ol {
        padding: 0;
        list-style: none;
    }

    #toc-content {
        padding-bottom: 30px;
        overflow: auto;
    }

    #toc-content ol {
        padding-left: 10px;
    }

    #toc-content ol li {
        padding-left: 10px;
    }

    #toc-content .toc-link:hover {
        color: #42b983;
        font-weight: 700;
        text-decoration: underline;
    }

    #toc-content .toc-link::before {
        background-color: transparent;
        max-height: 25px;

        position: absolute;
        right: 23.5vw;
        display: block;
    }

    #toc-content .is-active-link {
        color: #42b983;
    }

    #floating-toc-btn {
        position: fixed;
        right: 15px;
        bottom: 76px;
        padding-top: 15px;
        margin-bottom: 0;
        z-index: 998;
    }

    #floating-toc-btn .btn-floating {
        width: 48px;
        height: 48px;
    }

    #floating-toc-btn .btn-floating i {
        line-height: 48px;
        font-size: 1.4rem;
    }
</style>
<div class="row">
    <div id="main-content" class="col s12 m12 l9">
        <!-- 文章内容详情 -->
<div id="artDetail">
    <div class="card">
        <div class="card-content article-info">
            <div class="row tag-cate">
                <div class="col s7">
                    
                    <div class="article-tag">
                        
                            <a href="/blog/tags/Java/">
                                <span class="chip bg-color">Java</span>
                            </a>
                        
                            <a href="/blog/tags/JavaSE/">
                                <span class="chip bg-color">JavaSE</span>
                            </a>
                        
                    </div>
                    
                </div>
                <div class="col s5 right-align">
                    
                    <div class="post-cate">
                        <i class="fas fa-bookmark fa-fw icon-category"></i>
                        
                            <a href="/blog/categorie/JavaSE/" class="post-category">
                                JavaSE
                            </a>
                        
                    </div>
                    
                </div>
            </div>

            <div class="post-info">
                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-minus fa-fw"></i>发布日期:&nbsp;&nbsp;
                    2023-05-09
                </div>
                

                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-check fa-fw"></i>更新日期:&nbsp;&nbsp;
                    2023-05-09
                </div>
                

                
                <div class="info-break-policy">
                    <i class="far fa-file-word fa-fw"></i>文章字数:&nbsp;&nbsp;
                    12.2k
                </div>
                

                
                <div class="info-break-policy">
                    <i class="far fa-clock fa-fw"></i>阅读时长:&nbsp;&nbsp;
                    52 分
                </div>
                

                
                    <div id="busuanzi_container_page_pv" class="info-break-policy">
                        <i class="far fa-eye fa-fw"></i>阅读次数:&nbsp;&nbsp;
                        <span id="busuanzi_value_page_pv"></span>
                    </div>
				
            </div>
        </div>
        <hr class="clearfix">

        
        <!-- 是否加载使用自带的 prismjs. -->
        <link rel="stylesheet" href="/blog/libs/prism/prism.css">
        

        

        <div class="card-content article-card-content">
            <div id="articleContent">
                <h1 id="Java-正则从入门到精通"><a href="#Java-正则从入门到精通" class="headerlink" title="Java 正则从入门到精通"></a>Java 正则从入门到精通</h1><blockquote>
<p>关键词：Pattern、Matcher、捕获与非捕获、反向引用、零宽断言、贪婪与懒惰、元字符、DFA、NFA</p>
</blockquote>
<h2 id="正则简介"><a href="#正则简介" class="headerlink" title="正则简介"></a>正则简介</h2><h3 id="正则表达式是什么"><a href="#正则表达式是什么" class="headerlink" title="正则表达式是什么"></a>正则表达式是什么</h3><p>正则表达式（Regular Expression）是一个用正则符号写出的公式，程序对这个公式进行语法分析，建立一个语法分析树，再根据这个分析树结合正则表达式的引擎生成执行程序（这个执行程序我们把它称作状态机，也叫状态自动机），用于字符匹配。</p>
<h3 id="如何学习正则"><a href="#如何学习正则" class="headerlink" title="如何学习正则"></a>如何学习正则</h3><p>正则表达式是一个强大的文本匹配工具，但是它的规则很复杂，理解起来较为困难，容易让人望而生畏。</p>
<p>刚接触正则时，我看了一堆正则的语义说明，但是仍然不明所以。后来，我多接触一些正则的应用实例，渐渐有了感觉，再结合语义说明，终有领悟。我觉得正则表达式和武侠修练武功差不多，应该先练招式，再练心法。如果一开始就直接看正则的规则，保证你会懵逼。当你熟悉基本招式（正则基本使用案例）后，也该修炼修炼心法（正则语法）了。真正的高手不能只靠死记硬背那么几招把式。就像张三丰教张无忌太极拳一样，领悟心法，融会贯通，少侠你就可以无招胜有招，成为传说中的绝世高手。</p>
<p><strong>以上闲话可归纳为一句：学习正则应该从实例去理解规则。</strong></p>
<h2 id="正则工具类"><a href="#正则工具类" class="headerlink" title="正则工具类"></a>正则工具类</h2><p>JDK 中的 <code>java.util.regex</code> 包提供了对正则表达式的支持。</p>
<p><code>java.util.regex</code> 有三个核心类：</p>
<ul>
<li><strong>Pattern 类：</strong><code>Pattern</code> 是一个正则表达式的编译表示。</li>
<li><strong>Matcher 类：</strong><code>Matcher</code> 是对输入字符串进行解释和匹配操作的引擎。</li>
<li><strong>PatternSyntaxException：</strong><code>PatternSyntaxException</code> 是一个非强制异常类，它表示一个正则表达式模式中的语法错误。</li>
</ul>
<p><strong>注：</strong>需要格外注意一点，在 Java 中使用反斜杠”\“时必须写成 <code>"\\"</code>。所以本文的代码出现形如 <code>String regex = "\\$\\{.*?\\}"</code> 其实就是 <code>\$\{.\*?\}</code>。</p>
<h3 id="Pattern-类"><a href="#Pattern-类" class="headerlink" title="Pattern 类"></a>Pattern 类</h3><p><code>Pattern</code>类没有公共构造方法。要创建一个<code>Pattern</code>对象，你必须首先调用其<strong>静态方法</strong><code>compile</code>，加载正则规则字符串，然后返回一个 Pattern 对象。</p>
<p>与<code>Pattern</code>类一样，<code>Matcher</code>类也没有公共构造方法。你需要调用<code>Pattern</code>对象的<code>matcher</code>方法来获得一个<code>Matcher</code>对象。</p>
<p>【示例】Pattern 和 Matcher 的初始化</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">Pattern</span> p <span class="token operator">=</span> <span class="token class-name">Pattern</span><span class="token punctuation">.</span><span class="token function">compile</span><span class="token punctuation">(</span>regex<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Matcher</span> m <span class="token operator">=</span> p<span class="token punctuation">.</span><span class="token function">matcher</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>

<h3 id="Matcher-类"><a href="#Matcher-类" class="headerlink" title="Matcher 类"></a>Matcher 类</h3><p><code>Matcher</code> 类可以说是 <code>java.util.regex</code> 中的核心类，它有三类功能：校验、查找、替换。</p>
<h4 id="校验"><a href="#校验" class="headerlink" title="校验"></a>校验</h4><p>为了校验文本是否与正则规则匹配，Matcher 提供了以下几个返回值为 <code>boolean</code> 的方法。</p>
<table>
<thead>
<tr>
<th><strong>序号</strong></th>
<th><strong>方法及说明</strong></th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>**public boolean lookingAt() ** 尝试将从区域开头开始的输入序列与该模式匹配。</td>
</tr>
<tr>
<td>2</td>
<td>**public boolean find() **尝试查找与该模式匹配的输入序列的下一个子序列。</td>
</tr>
<tr>
<td>3</td>
<td><strong>public boolean find(int start）</strong>重置此匹配器，然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列。</td>
</tr>
<tr>
<td>4</td>
<td>**public boolean matches() **尝试将整个区域与模式匹配。</td>
</tr>
</tbody></table>
<p>如果你傻傻分不清上面的查找方法有什么区别，那么下面一个例子就可以让你秒懂。</p>
<p>【示例】lookingAt、find、matches</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token function">checkLookingAt</span><span class="token punctuation">(</span><span class="token string">"hello"</span><span class="token punctuation">,</span> <span class="token string">"helloworld"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token function">checkLookingAt</span><span class="token punctuation">(</span><span class="token string">"world"</span><span class="token punctuation">,</span> <span class="token string">"helloworld"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token function">checkFind</span><span class="token punctuation">(</span><span class="token string">"hello"</span><span class="token punctuation">,</span> <span class="token string">"helloworld"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token function">checkFind</span><span class="token punctuation">(</span><span class="token string">"world"</span><span class="token punctuation">,</span> <span class="token string">"helloworld"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"hello"</span><span class="token punctuation">,</span> <span class="token string">"helloworld"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"world"</span><span class="token punctuation">,</span> <span class="token string">"helloworld"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"helloworld"</span><span class="token punctuation">,</span> <span class="token string">"helloworld"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">checkLookingAt</span><span class="token punctuation">(</span><span class="token class-name">String</span> regex<span class="token punctuation">,</span> <span class="token class-name">String</span> content<span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token class-name">Pattern</span> p <span class="token operator">=</span> <span class="token class-name">Pattern</span><span class="token punctuation">.</span><span class="token function">compile</span><span class="token punctuation">(</span>regex<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">Matcher</span> m <span class="token operator">=</span> p<span class="token punctuation">.</span><span class="token function">matcher</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>m<span class="token punctuation">.</span><span class="token function">lookingAt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>content <span class="token operator">+</span> <span class="token string">"\tlookingAt： "</span> <span class="token operator">+</span> regex<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>content <span class="token operator">+</span> <span class="token string">"\tnot lookingAt： "</span> <span class="token operator">+</span> regex<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">checkFind</span><span class="token punctuation">(</span><span class="token class-name">String</span> regex<span class="token punctuation">,</span> <span class="token class-name">String</span> content<span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token class-name">Pattern</span> p <span class="token operator">=</span> <span class="token class-name">Pattern</span><span class="token punctuation">.</span><span class="token function">compile</span><span class="token punctuation">(</span>regex<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">Matcher</span> m <span class="token operator">=</span> p<span class="token punctuation">.</span><span class="token function">matcher</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>m<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>content <span class="token operator">+</span> <span class="token string">"\tfind： "</span> <span class="token operator">+</span> regex<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>content <span class="token operator">+</span> <span class="token string">"\tnot find： "</span> <span class="token operator">+</span> regex<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token class-name">String</span> regex<span class="token punctuation">,</span> <span class="token class-name">String</span> content<span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token class-name">Pattern</span> p <span class="token operator">=</span> <span class="token class-name">Pattern</span><span class="token punctuation">.</span><span class="token function">compile</span><span class="token punctuation">(</span>regex<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">Matcher</span> m <span class="token operator">=</span> p<span class="token punctuation">.</span><span class="token function">matcher</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>m<span class="token punctuation">.</span><span class="token function">matches</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>content <span class="token operator">+</span> <span class="token string">"\tmatches： "</span> <span class="token operator">+</span> regex<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>content <span class="token operator">+</span> <span class="token string">"\tnot matches： "</span> <span class="token operator">+</span> regex<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>输出：</p>
<pre class="line-numbers language-none"><code class="language-none">helloworld	lookingAt： hello
helloworld	not lookingAt： world
helloworld	find： hello
helloworld	find： world
helloworld	not matches： hello
helloworld	not matches： world
helloworld	matches： helloworld<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p><strong>说明</strong></p>
<p><code>regex = "world"</code> 表示的正则规则是以 world 开头的字符串，<code>regex = "hello"</code> 和 <code>regex = "helloworld"</code> 也是同理。</p>
<ul>
<li><code>lookingAt</code>方法从头部开始，检查 content 字符串是否有子字符串于正则规则匹配。</li>
<li><code>find</code>方法检查 content 字符串是否有子字符串于正则规则匹配，不管字符串所在位置。</li>
<li><code>matches</code>方法检查 content 字符串整体是否与正则规则匹配。</li>
</ul>
<h4 id="查找"><a href="#查找" class="headerlink" title="查找"></a>查找</h4><p>为了查找文本匹配正则规则的位置，<code>Matcher</code>提供了以下方法：</p>
<table>
<thead>
<tr>
<th><strong>序号</strong></th>
<th><strong>方法及说明</strong></th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>**public int start() **返回以前匹配的初始索引。</td>
</tr>
<tr>
<td>2</td>
<td><strong>public int start(int group)</strong> 返回在以前的匹配操作期间，由给定组所捕获的子序列的初始索引</td>
</tr>
<tr>
<td>3</td>
<td>**public int end()**返回最后匹配字符之后的偏移量。</td>
</tr>
<tr>
<td>4</td>
<td>**public int end(int group)**返回在以前的匹配操作期间，由给定组所捕获子序列的最后字符之后的偏移量。</td>
</tr>
<tr>
<td>5</td>
<td>**public String group()**返回前一个符合匹配条件的子序列。</td>
</tr>
<tr>
<td>6</td>
<td>**public String group(int group)**返回指定的符合匹配条件的子序列。</td>
</tr>
</tbody></table>
<p>【示例】使用 start()、end()、group() 查找所有匹配正则条件的子序列</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">final</span> <span class="token class-name">String</span> regex <span class="token operator">=</span> <span class="token string">"world"</span><span class="token punctuation">;</span>
	<span class="token keyword">final</span> <span class="token class-name">String</span> content <span class="token operator">=</span> <span class="token string">"helloworld helloworld"</span><span class="token punctuation">;</span>
	<span class="token class-name">Pattern</span> p <span class="token operator">=</span> <span class="token class-name">Pattern</span><span class="token punctuation">.</span><span class="token function">compile</span><span class="token punctuation">(</span>regex<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">Matcher</span> m <span class="token operator">=</span> p<span class="token punctuation">.</span><span class="token function">matcher</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"content: "</span> <span class="token operator">+</span> content<span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
	<span class="token keyword">while</span> <span class="token punctuation">(</span>m<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		i<span class="token operator">++</span><span class="token punctuation">;</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"["</span> <span class="token operator">+</span> i <span class="token operator">+</span> <span class="token string">"th] found"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">print</span><span class="token punctuation">(</span><span class="token string">"start: "</span> <span class="token operator">+</span> m<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">", "</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">print</span><span class="token punctuation">(</span><span class="token string">"end: "</span> <span class="token operator">+</span> m<span class="token punctuation">.</span><span class="token function">end</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">", "</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">print</span><span class="token punctuation">(</span><span class="token string">"group: "</span> <span class="token operator">+</span> m<span class="token punctuation">.</span><span class="token function">group</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p><strong>输出</strong></p>
<pre class="line-numbers language-none"><code class="language-none">content: helloworld helloworld
[1th] found
start: 5, end: 10, group: world
[2th] found
start: 16, end: 21, group: world<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p><strong>说明</strong></p>
<p>例子很直白，不言自明了吧。</p>
<h4 id="替换"><a href="#替换" class="headerlink" title="替换"></a>替换</h4><p>替换方法是替换输入字符串里文本的方法：</p>
<table>
<thead>
<tr>
<th><strong>序号</strong></th>
<th><strong>方法及说明</strong></th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>**public Matcher appendReplacement(StringBuffer sb, String replacement)**实现非终端添加和替换步骤。</td>
</tr>
<tr>
<td>2</td>
<td>**public StringBuffer appendTail(StringBuffer sb)**实现终端添加和替换步骤。</td>
</tr>
<tr>
<td>3</td>
<td>**public String replaceAll(String replacement) ** 替换模式与给定替换字符串相匹配的输入序列的每个子序列。</td>
</tr>
<tr>
<td>4</td>
<td><strong>public String replaceFirst(String replacement)</strong> 替换模式与给定替换字符串匹配的输入序列的第一个子序列。</td>
</tr>
<tr>
<td>5</td>
<td>**public static String quoteReplacement(String s)**返回指定字符串的字面替换字符串。这个方法返回一个字符串，就像传递给 Matcher 类的 appendReplacement 方法一个字面字符串一样工作。</td>
</tr>
</tbody></table>
<p>【示例】replaceFirst 和 replaceAll</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token class-name">String</span> regex <span class="token operator">=</span> <span class="token string">"can"</span><span class="token punctuation">;</span>
	<span class="token class-name">String</span> replace <span class="token operator">=</span> <span class="token string">"can not"</span><span class="token punctuation">;</span>
	<span class="token class-name">String</span> content <span class="token operator">=</span> <span class="token string">"I can because I think I can."</span><span class="token punctuation">;</span>

	<span class="token class-name">Pattern</span> p <span class="token operator">=</span> <span class="token class-name">Pattern</span><span class="token punctuation">.</span><span class="token function">compile</span><span class="token punctuation">(</span>regex<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">Matcher</span> m <span class="token operator">=</span> p<span class="token punctuation">.</span><span class="token function">matcher</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"content: "</span> <span class="token operator">+</span> content<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"replaceFirst: "</span> <span class="token operator">+</span> m<span class="token punctuation">.</span><span class="token function">replaceFirst</span><span class="token punctuation">(</span>replace<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"replaceAll: "</span> <span class="token operator">+</span> m<span class="token punctuation">.</span><span class="token function">replaceAll</span><span class="token punctuation">(</span>replace<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p><strong>输出</strong></p>
<pre class="line-numbers language-none"><code class="language-none">content: I can because I think I can.
replaceFirst: I can not because I think I can.
replaceAll: I can not because I think I can not.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre>

<p><strong>说明</strong></p>
<p>replaceFirst：替换第一个匹配正则规则的子序列。</p>
<p>replaceAll：替换所有匹配正则规则的子序列。</p>
<p>【示例】appendReplacement、appendTail 和 replaceAll</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token class-name">String</span> regex <span class="token operator">=</span> <span class="token string">"can"</span><span class="token punctuation">;</span>
	<span class="token class-name">String</span> replace <span class="token operator">=</span> <span class="token string">"can not"</span><span class="token punctuation">;</span>
	<span class="token class-name">String</span> content <span class="token operator">=</span> <span class="token string">"I can because I think I can."</span><span class="token punctuation">;</span>
	<span class="token class-name">StringBuffer</span> sb <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StringBuffer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">StringBuffer</span> sb2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StringBuffer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"content: "</span> <span class="token operator">+</span> content<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">Pattern</span> p <span class="token operator">=</span> <span class="token class-name">Pattern</span><span class="token punctuation">.</span><span class="token function">compile</span><span class="token punctuation">(</span>regex<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">Matcher</span> m <span class="token operator">=</span> p<span class="token punctuation">.</span><span class="token function">matcher</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">while</span> <span class="token punctuation">(</span>m<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		m<span class="token punctuation">.</span><span class="token function">appendReplacement</span><span class="token punctuation">(</span>sb<span class="token punctuation">,</span> replace<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"appendReplacement: "</span> <span class="token operator">+</span> sb<span class="token punctuation">)</span><span class="token punctuation">;</span>
	m<span class="token punctuation">.</span><span class="token function">appendTail</span><span class="token punctuation">(</span>sb<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"appendTail: "</span> <span class="token operator">+</span> sb<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p><strong>输出</strong></p>
<pre class="line-numbers language-none"><code class="language-none">content: I can because I think I can.
appendReplacement: I can not because I think I can not
appendTail: I can not because I think I can not.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre>

<p><strong>说明</strong></p>
<p>从输出结果可以看出，<code>appendReplacement</code>和<code>appendTail</code>方法组合起来用，功能和<code>replaceAll</code>是一样的。</p>
<p>如果你查看<code>replaceAll</code>的源码，会发现其内部就是使用<code>appendReplacement</code>和<code>appendTail</code>方法组合来实现的。</p>
<p>【示例】quoteReplacement 和 replaceAll，解决特殊字符替换问题</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token class-name">String</span> regex <span class="token operator">=</span> <span class="token string">"\\$\\{.*?\\}"</span><span class="token punctuation">;</span>
	<span class="token class-name">String</span> replace <span class="token operator">=</span> <span class="token string">"${product}"</span><span class="token punctuation">;</span>
	<span class="token class-name">String</span> content <span class="token operator">=</span> <span class="token string">"product is ${productName}."</span><span class="token punctuation">;</span>

	<span class="token class-name">Pattern</span> p <span class="token operator">=</span> <span class="token class-name">Pattern</span><span class="token punctuation">.</span><span class="token function">compile</span><span class="token punctuation">(</span>regex<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">Matcher</span> m <span class="token operator">=</span> p<span class="token punctuation">.</span><span class="token function">matcher</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">String</span> replaceAll <span class="token operator">=</span> m<span class="token punctuation">.</span><span class="token function">replaceAll</span><span class="token punctuation">(</span>replace<span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"content: "</span> <span class="token operator">+</span> content<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"replaceAll: "</span> <span class="token operator">+</span> replaceAll<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p><strong>输出</strong></p>
<pre class="line-numbers language-none"><code class="language-none">Exception in thread "main" java.lang.IllegalArgumentException: No group with name {product}
	at java.util.regex.Matcher.appendReplacement(Matcher.java:849)
	at java.util.regex.Matcher.replaceAll(Matcher.java:955)
	at org.zp.notes.javase.regex.RegexDemo.wrongMethod(RegexDemo.java:42)
	at org.zp.notes.javase.regex.RegexDemo.main(RegexDemo.java:18)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p><strong>说明</strong></p>
<p><code>String regex = "\\$\\{.*?\\}";</code>表示匹配类似<code>${name}</code>这样的字符串。由于<code>$</code>、<code>{</code> 、<code>}</code>都是特殊字符，需要用反义字符<code>\</code>来修饰才能被当做一个字符串字符来处理。</p>
<p>上面的例子是想将 <code>${productName}</code> 替换为 <code>${product}</code> ，然而<code>replaceAll</code>方法却将传入的字符串中的<code>$</code>当做特殊字符来处理了。结果产生异常。</p>
<p>如何解决这个问题?</p>
<p>JDK1.5 引入了<code>quoteReplacement</code>方法。它可以用来转换特殊字符。其实源码非常简单，就是判断字符串中如果有<code>\</code>或<code>$</code>，就为它加一个转义字符<code>\</code></p>
<p>我们对上面的代码略作调整：</p>
<p><code>m.replaceAll(replace)</code>改为<code>m.replaceAll(Matcher.quoteReplacement(replace))</code>，新代码如下：</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token class-name">String</span> regex <span class="token operator">=</span> <span class="token string">"\\$\\{.*?\\}"</span><span class="token punctuation">;</span>
	<span class="token class-name">String</span> replace <span class="token operator">=</span> <span class="token string">"${product}"</span><span class="token punctuation">;</span>
	<span class="token class-name">String</span> content <span class="token operator">=</span> <span class="token string">"product is ${productName}."</span><span class="token punctuation">;</span>

	<span class="token class-name">Pattern</span> p <span class="token operator">=</span> <span class="token class-name">Pattern</span><span class="token punctuation">.</span><span class="token function">compile</span><span class="token punctuation">(</span>regex<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">Matcher</span> m <span class="token operator">=</span> p<span class="token punctuation">.</span><span class="token function">matcher</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">String</span> replaceAll <span class="token operator">=</span> m<span class="token punctuation">.</span><span class="token function">replaceAll</span><span class="token punctuation">(</span><span class="token class-name">Matcher</span><span class="token punctuation">.</span><span class="token function">quoteReplacement</span><span class="token punctuation">(</span>replace<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"content: "</span> <span class="token operator">+</span> content<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"replaceAll: "</span> <span class="token operator">+</span> replaceAll<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p><strong>输出</strong></p>
<pre class="line-numbers language-none"><code class="language-none">content: product is ${productName}.
replaceAll: product is ${product}.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>

<p><strong>说明</strong></p>
<p>字符串中如果有<code>\</code>或<code>$</code>，不能被正常解析的问题解决。</p>
<h2 id="元字符"><a href="#元字符" class="headerlink" title="元字符"></a>元字符</h2><p>元字符(metacharacters)就是正则表达式中具有特殊意义的专用字符。</p>
<h3 id="基本元字符"><a href="#基本元字符" class="headerlink" title="基本元字符"></a>基本元字符</h3><p>正则表达式的元字符难以记忆，很大程度上是因为有很多为了简化表达而出现的等价字符。而实际上最基本的元字符，并没有那么多。对于大部分的场景，基本元字符都可以搞定。让我们从一个个实例出发，由浅入深的去体会正则的奥妙。</p>
<h4 id="多选（-）"><a href="#多选（-）" class="headerlink" title="多选（|）"></a>多选（<code>|</code>）</h4><p>【示例】匹配一个确定的字符串</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"abc"</span><span class="token punctuation">,</span> <span class="token string">"abc"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<p>如果要匹配一个确定的字符串，非常简单，如例 1 所示。但是，如果你不确定要匹配的字符串，希望有多个选择，怎么办？答案是：使用元字符<code>|</code> ，它的含义是或。</p>
<p>【示例】匹配多个可选的字符串</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// 测试正则表达式字符：|</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"yes|no"</span><span class="token punctuation">,</span> <span class="token string">"yes"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"yes|no"</span><span class="token punctuation">,</span> <span class="token string">"no"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"yes|no"</span><span class="token punctuation">,</span> <span class="token string">"right"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 输出</span>
<span class="token comment">// yes	matches： yes|no</span>
<span class="token comment">// no	matches： yes|no</span>
<span class="token comment">// right	not matches： yes|no</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<h4 id="分组（-）"><a href="#分组（-）" class="headerlink" title="分组（()）"></a>分组（<code>()</code>）</h4><p>如果你希望表达式由多个子表达式组成，你可以使用 <code>()</code>。</p>
<p>【示例】匹配组合字符串</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"(play|end)(ing|ed)"</span><span class="token punctuation">,</span> <span class="token string">"ended"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"(play|end)(ing|ed)"</span><span class="token punctuation">,</span> <span class="token string">"ending"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"(play|end)(ing|ed)"</span><span class="token punctuation">,</span> <span class="token string">"playing"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"(play|end)(ing|ed)"</span><span class="token punctuation">,</span> <span class="token string">"played"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 输出</span>
<span class="token comment">// ended	matches： (play|end)(ing|ed)</span>
<span class="token comment">// ending	matches： (play|end)(ing|ed)</span>
<span class="token comment">// playing	matches： (play|end)(ing|ed)</span>
<span class="token comment">// played	matches： (play|end)(ing|ed)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<h4 id="指定单字符有效范围（-）"><a href="#指定单字符有效范围（-）" class="headerlink" title="指定单字符有效范围（[]）"></a>指定单字符有效范围（<code>[]</code>）</h4><p>前面展示了如何匹配字符串，但是很多时候你需要精确的匹配一个字符，这时可以使用<code>[]</code> 。</p>
<p>【示例】字符在指定范围</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// 测试正则表达式字符：[]</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"[abc]"</span><span class="token punctuation">,</span> <span class="token string">"b"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// 字符只能是a、b、c</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"[a-z]"</span><span class="token punctuation">,</span> <span class="token string">"m"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 字符只能是a - z</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"[A-Z]"</span><span class="token punctuation">,</span> <span class="token string">"O"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 字符只能是A - Z</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"[a-zA-Z]"</span><span class="token punctuation">,</span> <span class="token string">"K"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 字符只能是a - z和A - Z</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"[a-zA-Z]"</span><span class="token punctuation">,</span> <span class="token string">"k"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"[0-9]"</span><span class="token punctuation">,</span> <span class="token string">"5"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 字符只能是0 - 9</span>

<span class="token comment">// 输出</span>
<span class="token comment">// b	matches： [abc]</span>
<span class="token comment">// m	matches： [a-z]</span>
<span class="token comment">// O	matches： [A-Z]</span>
<span class="token comment">// K	matches： [a-zA-Z]</span>
<span class="token comment">// k	matches： [a-zA-Z]</span>
<span class="token comment">// 5	matches： [0-9]</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<h4 id="指定单字符无效范围（-）"><a href="#指定单字符无效范围（-）" class="headerlink" title="指定单字符无效范围（ [^]）"></a>指定单字符无效范围（ <code>[^]</code>）</h4><p>【示例】字符不能在指定范围</p>
<p>如果需要匹配一个字符的逆操作，即字符不能在指定范围，可以使用<code>[^]</code>。</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// 测试正则表达式字符：[^]</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"[^abc]"</span><span class="token punctuation">,</span> <span class="token string">"b"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 字符不能是a、b、c</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"[^a-z]"</span><span class="token punctuation">,</span> <span class="token string">"m"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 字符不能是a - z</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"[^A-Z]"</span><span class="token punctuation">,</span> <span class="token string">"O"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 字符不能是A - Z</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"[^a-zA-Z]"</span><span class="token punctuation">,</span> <span class="token string">"K"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 字符不能是a - z和A - Z</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"[^a-zA-Z]"</span><span class="token punctuation">,</span> <span class="token string">"k"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"[^0-9]"</span><span class="token punctuation">,</span> <span class="token string">"5"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 字符不能是0 - 9</span>

<span class="token comment">// 输出</span>
<span class="token comment">// b	not matches： [^abc]</span>
<span class="token comment">// m	not matches： [^a-z]</span>
<span class="token comment">// O	not matches： [^A-Z]</span>
<span class="token comment">// K	not matches： [^a-zA-Z]</span>
<span class="token comment">// k	not matches： [^a-zA-Z]</span>
<span class="token comment">// 5	not matches： [^0-9]</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<h4 id="限制字符数量（-）"><a href="#限制字符数量（-）" class="headerlink" title="限制字符数量（{}）"></a>限制字符数量（<code>{}</code>）</h4><p>如果想要控制字符出现的次数，可以使用 <code>{}</code>。</p>
<table>
<thead>
<tr>
<th>字符</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td><code>{n}</code></td>
<td>n 是一个非负整数。匹配确定的 n 次。</td>
</tr>
<tr>
<td><code>{n,}</code></td>
<td>n 是一个非负整数。至少匹配 n 次。</td>
</tr>
<tr>
<td><code>{n,m}</code></td>
<td>m 和 n 均为非负整数，其中 n &lt;= m。最少匹配 n 次且最多匹配 m 次。</td>
</tr>
</tbody></table>
<p>【示例】限制字符出现次数</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// {n}: n 是一个非负整数。匹配确定的 n 次。</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap{1}"</span><span class="token punctuation">,</span> <span class="token string">"a"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap{1}"</span><span class="token punctuation">,</span> <span class="token string">"ap"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap{1}"</span><span class="token punctuation">,</span> <span class="token string">"app"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap{1}"</span><span class="token punctuation">,</span> <span class="token string">"apppppppppp"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// {n,}: n 是一个非负整数。至少匹配 n 次。</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap{1,}"</span><span class="token punctuation">,</span> <span class="token string">"a"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap{1,}"</span><span class="token punctuation">,</span> <span class="token string">"ap"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap{1,}"</span><span class="token punctuation">,</span> <span class="token string">"app"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap{1,}"</span><span class="token punctuation">,</span> <span class="token string">"apppppppppp"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// {n,m}: m 和 n 均为非负整数，其中 n &lt;= m。最少匹配 n 次且最多匹配 m 次。</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap{2,5}"</span><span class="token punctuation">,</span> <span class="token string">"a"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap{2,5}"</span><span class="token punctuation">,</span> <span class="token string">"ap"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap{2,5}"</span><span class="token punctuation">,</span> <span class="token string">"app"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap{2,5}"</span><span class="token punctuation">,</span> <span class="token string">"apppppppppp"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 输出</span>
<span class="token comment">// a	not matches： ap{1}</span>
<span class="token comment">// ap	matches： ap{1}</span>
<span class="token comment">// app	not matches： ap{1}</span>
<span class="token comment">// apppppppppp	not matches： ap{1}</span>
<span class="token comment">// a	not matches： ap{1,}</span>
<span class="token comment">// ap	matches： ap{1,}</span>
<span class="token comment">// app	matches： ap{1,}</span>
<span class="token comment">// apppppppppp	matches： ap{1,}</span>
<span class="token comment">// a	not matches： ap{2,5}</span>
<span class="token comment">// ap	not matches： ap{2,5}</span>
<span class="token comment">// app	matches： ap{2,5}</span>
<span class="token comment">// apppppppppp	not matches： ap{2,5}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<h4 id="转义字符（-）"><a href="#转义字符（-）" class="headerlink" title="转义字符（/）"></a>转义字符（<code>/</code>）</h4><p>如果想要查找元字符本身，你需要使用转义符，使得正则引擎将其视作一个普通字符，而不是一个元字符去处理。</p>
<pre class="line-numbers language-none"><code class="language-none">* 的转义字符：\*
+ 的转义字符：\+
? 的转义字符：\?
^ 的转义字符：\^
$ 的转义字符：\$
. 的转义字符：\.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>如果是转义符 <code>\</code> 本身，你需要使用 <code>\\</code> 。</p>
<h4 id="指定表达式字符串的开始（-）和结尾（-）"><a href="#指定表达式字符串的开始（-）和结尾（-）" class="headerlink" title="指定表达式字符串的开始（^）和结尾（$）"></a>指定表达式字符串的开始（<code>^</code>）和结尾（<code>$</code>）</h4><p>如果希望匹配的字符串必须以特定字符串开头，可以使用 <code>^</code> 。</p>
<blockquote>
<p>注意：请特别留意，这里的 <code>^</code> 一定要和 <code>[^]</code> 中的 <code>^</code> 区分。</p>
</blockquote>
<p>【示例】限制字符串头部</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"^app[a-z]{0,}"</span><span class="token punctuation">,</span> <span class="token string">"apple"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 字符串必须以app开头</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"^app[a-z]{0,}"</span><span class="token punctuation">,</span> <span class="token string">"aplause"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 输出</span>
<span class="token comment">// apple	matches： ^app[a-z]{0,}</span>
<span class="token comment">// aplause	not matches： ^app[a-z]{0,}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>如果希望匹配的字符串必须以特定字符串结尾，可以使用 <code>$</code> 。</p>
<p>【示例】限制字符串尾部</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"[a-z]{0,}ing$"</span><span class="token punctuation">,</span> <span class="token string">"playing"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 字符串必须以ing结尾</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"[a-z]{0,}ing$"</span><span class="token punctuation">,</span> <span class="token string">"long"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 输出</span>
<span class="token comment">// playing	matches： [a-z]{0,}ing$</span>
<span class="token comment">// long	not matches： [a-z]{0,}ing$</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<h3 id="等价字符"><a href="#等价字符" class="headerlink" title="等价字符"></a>等价字符</h3><p>等价字符，顾名思义，就是对于基本元字符表达的一种简化（等价字符的功能都可以通过基本元字符来实现）。</p>
<p>在没有掌握基本元字符之前，可以先不用理会，因为很容易把人绕晕。</p>
<p>等价字符的好处在于简化了基本元字符的写法。</p>
<h4 id="表示某一类型字符的等价字符"><a href="#表示某一类型字符的等价字符" class="headerlink" title="表示某一类型字符的等价字符"></a>表示某一类型字符的等价字符</h4><p>下表中的等价字符都表示某一类型的字符。</p>
<table>
<thead>
<tr>
<th>字符</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td><strong><code>.</code></strong></td>
<td>匹配除“\n”之外的任何单个字符。</td>
</tr>
<tr>
<td><strong><code>\d</code></strong></td>
<td>匹配一个数字字符。等价于[0-9]。</td>
</tr>
<tr>
<td><strong><code>\D</code></strong></td>
<td>匹配一个非数字字符。等价于[^0-9]。</td>
</tr>
<tr>
<td><strong><code>\w</code></strong></td>
<td>匹配包括下划线的任何单词字符。类似但不等价于“[A-Za-z0-9_]”，这里的单词字符指的是 Unicode 字符集。</td>
</tr>
<tr>
<td><strong><code>\W</code></strong></td>
<td>匹配任何非单词字符。</td>
</tr>
<tr>
<td><strong><code>\s</code></strong></td>
<td>匹配任何不可见字符，包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。</td>
</tr>
<tr>
<td><strong><code>\S</code></strong></td>
<td>匹配任何可见字符。等价于[ \f\n\r\t\v]。</td>
</tr>
</tbody></table>
<p>【示例】基本等价字符的用法</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// 匹配除“\n”之外的任何单个字符</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">".{1,}"</span><span class="token punctuation">,</span> <span class="token string">"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">".{1,}"</span><span class="token punctuation">,</span> <span class="token string">"~!@#$%^&amp;*()+`-=[]{};:&lt;&gt;,./?|\\"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"."</span><span class="token punctuation">,</span> <span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"[^\n]"</span><span class="token punctuation">,</span> <span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 匹配一个数字字符。等价于[0-9]</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"\\d{1,}"</span><span class="token punctuation">,</span> <span class="token string">"0123456789"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 匹配一个非数字字符。等价于[^0-9]</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"\\D{1,}"</span><span class="token punctuation">,</span> <span class="token string">"0123456789"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 匹配包括下划线的任何单词字符。类似但不等价于“[A-Za-z0-9_]”，这里的单词字符指的是Unicode字符集</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"\\w{1,}"</span><span class="token punctuation">,</span> <span class="token string">"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"\\w{1,}"</span><span class="token punctuation">,</span> <span class="token string">"~!@#$%^&amp;*()+`-=[]{};:&lt;&gt;,./?|\\"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 匹配任何非单词字符</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"\\W{1,}"</span><span class="token punctuation">,</span> <span class="token string">"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"\\W{1,}"</span><span class="token punctuation">,</span> <span class="token string">"~!@#$%^&amp;*()+`-=[]{};:&lt;&gt;,./?|\\"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 匹配任何不可见字符，包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"\\s{1,}"</span><span class="token punctuation">,</span> <span class="token string">" \f\r\n\t"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 匹配任何可见字符。等价于[^ \f\n\r\t\v]</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"\\S{1,}"</span><span class="token punctuation">,</span> <span class="token string">" \f\r\n\t"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 输出</span>
<span class="token comment">// ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_	matches： .{1,}</span>
<span class="token comment">// ~!@#$%^&amp;*()+`-=[]{};:&lt;&gt;,./?|\\	matches： .{1,}</span>
<span class="token comment">// \n	not matches： .</span>
<span class="token comment">// \n	not matches： [^\n]</span>
<span class="token comment">// 0123456789	matches： \\d{1,}</span>
<span class="token comment">// 0123456789	not matches： \\D{1,}</span>
<span class="token comment">// ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_	matches： \\w{1,}</span>
<span class="token comment">// ~!@#$%^&amp;*()+`-=[]{};:&lt;&gt;,./?|\\	not matches： \\w{1,}</span>
<span class="token comment">// ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_	not matches： \\W{1,}</span>
<span class="token comment">// ~!@#$%^&amp;*()+`-=[]{};:&lt;&gt;,./?|\\	matches： \\W{1,}</span>
<span class="token comment">// \f\r\n\t	matches： \\s{1,}</span>
<span class="token comment">// \f\r\n\t	not matches： \\S{1,}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<h4 id="限制字符数量的等价字符"><a href="#限制字符数量的等价字符" class="headerlink" title="限制字符数量的等价字符"></a>限制字符数量的等价字符</h4><p>在基本元字符章节中，已经介绍了限制字符数量的基本元字符 - <code>{}</code> 。</p>
<p>此外，还有 <code>*</code>、<code>+</code>、<code>?</code> 这个三个为了简化写法而出现的等价字符，我们来认识一下。</p>
<table>
<thead>
<tr>
<th>字符</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td><code>*</code></td>
<td>匹配前面的子表达式零次或多次。等价于{0,}。</td>
</tr>
<tr>
<td><code>+</code></td>
<td>匹配前面的子表达式一次或多次。等价于{1,}。</td>
</tr>
<tr>
<td><code>?</code></td>
<td>匹配前面的子表达式零次或一次。等价于 {0,1}。</td>
</tr>
</tbody></table>
<p><strong>案例 限制字符数量的等价字符</strong></p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// *: 匹配前面的子表达式零次或多次。* 等价于{0,}。</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap*"</span><span class="token punctuation">,</span> <span class="token string">"a"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap*"</span><span class="token punctuation">,</span> <span class="token string">"ap"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap*"</span><span class="token punctuation">,</span> <span class="token string">"app"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap*"</span><span class="token punctuation">,</span> <span class="token string">"apppppppppp"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// +: 匹配前面的子表达式一次或多次。+ 等价于 {1,}。</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap+"</span><span class="token punctuation">,</span> <span class="token string">"a"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap+"</span><span class="token punctuation">,</span> <span class="token string">"ap"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap+"</span><span class="token punctuation">,</span> <span class="token string">"app"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap+"</span><span class="token punctuation">,</span> <span class="token string">"apppppppppp"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// ?: 匹配前面的子表达式零次或一次。? 等价于 {0,1}。</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap?"</span><span class="token punctuation">,</span> <span class="token string">"a"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap?"</span><span class="token punctuation">,</span> <span class="token string">"ap"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap?"</span><span class="token punctuation">,</span> <span class="token string">"app"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token string">"ap?"</span><span class="token punctuation">,</span> <span class="token string">"apppppppppp"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 输出</span>
<span class="token comment">// a	matches： ap*</span>
<span class="token comment">// ap	matches： ap*</span>
<span class="token comment">// app	matches： ap*</span>
<span class="token comment">// apppppppppp	matches： ap*</span>
<span class="token comment">// a	not matches： ap+</span>
<span class="token comment">// ap	matches： ap+</span>
<span class="token comment">// app	matches： ap+</span>
<span class="token comment">// apppppppppp	matches： ap+</span>
<span class="token comment">// a	matches： ap?</span>
<span class="token comment">// ap	matches： ap?</span>
<span class="token comment">// app	not matches： ap?</span>
<span class="token comment">// apppppppppp	not matches： ap?</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<h4 id="元字符优先级顺序"><a href="#元字符优先级顺序" class="headerlink" title="元字符优先级顺序"></a>元字符优先级顺序</h4><p>正则表达式从左到右进行计算，并遵循优先级顺序，这与算术表达式非常类似。</p>
<p>下表从最高到最低说明了各种正则表达式运算符的优先级顺序：</p>
<table>
<thead>
<tr>
<th>运算符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><code>\</code></td>
<td>转义符</td>
</tr>
<tr>
<td><code>()</code>、<code>(?:)</code>、<code>(?=)</code>、<code>[]</code></td>
<td>括号和中括号</td>
</tr>
<tr>
<td><code>*</code>、<code>+</code>、<code>?</code>、<code>{n}</code>、<code>{n,}</code>、<code>{n,m}</code></td>
<td>限定符</td>
</tr>
<tr>
<td><code>^</code>、<code>$</code>、<code>*任何字符</code>、<code>任何字符*</code></td>
<td>定位点和序列</td>
</tr>
<tr>
<td>`</td>
<td>`</td>
</tr>
</tbody></table>
<p>字符具有高于替换运算符的优先级，使得 <code>m|food</code> 匹配 <code>m</code> 或 <code>food</code> 。若要匹配 <code>mood</code> 或 <code>food</code> ，请使用括号创建子表达式，从而产生 <code>(m|f)ood</code> 。</p>
<h2 id="分组构造"><a href="#分组构造" class="headerlink" title="分组构造"></a>分组构造</h2><p>在基本元字符章节，提到了 <code>()</code> 字符可以用来对表达式分组。实际上分组还有更多复杂的用法。</p>
<p>所谓分组构造，是用来描述正则表达式的子表达式，用于捕获字符串中的子字符串。</p>
<h3 id="捕获与非捕获"><a href="#捕获与非捕获" class="headerlink" title="捕获与非捕获"></a>捕获与非捕获</h3><p>下表为分组构造中的捕获和非捕获分类。</p>
<table>
<thead>
<tr>
<th>表达式</th>
<th>描述</th>
<th>捕获或非捕获</th>
</tr>
</thead>
<tbody><tr>
<td><code>(exp)</code></td>
<td>匹配的子表达式</td>
<td>捕获</td>
</tr>
<tr>
<td><code>(?&lt;name&gt;exp)</code></td>
<td>命名的反向引用</td>
<td>捕获</td>
</tr>
<tr>
<td><code>(?:exp)</code></td>
<td>非捕获组</td>
<td>非捕获</td>
</tr>
<tr>
<td><code>(?=exp)</code></td>
<td>零宽度正预测先行断言</td>
<td>非捕获</td>
</tr>
<tr>
<td><code>(?!exp)</code></td>
<td>零宽度负预测先行断言</td>
<td>非捕获</td>
</tr>
<tr>
<td><code>(?&lt;=exp)</code></td>
<td>零宽度正回顾后发断言</td>
<td>非捕获</td>
</tr>
<tr>
<td><code>(?&lt;!exp)</code></td>
<td>零宽度负回顾后发断言</td>
<td>非捕获</td>
</tr>
</tbody></table>
<blockquote>
<p>注：Java 正则引擎不支持平衡组。</p>
</blockquote>
<h3 id="反向引用"><a href="#反向引用" class="headerlink" title="反向引用"></a>反向引用</h3><h5 id="带编号的反向引用"><a href="#带编号的反向引用" class="headerlink" title="带编号的反向引用"></a>带编号的反向引用</h5><p>带编号的反向引用使用以下语法：<code>\number</code></p>
<p>其中<em>number</em> 是正则表达式中捕获组的序号位置。 例如，\4 匹配第四个捕获组的内容。 如果正则表达式模式中未定义<em>number</em>，则将发生分析错误</p>
<p><strong>【示例】匹配重复的单词和紧随每个重复的单词的单词(不命名子表达式)</strong></p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// (\w+)\s\1\W(\w+) 匹配重复的单词和紧随每个重复的单词的单词</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"(\\w+)\\s\\1\\W(\\w+)"</span><span class="token punctuation">,</span>
		<span class="token string">"He said that that was the the correct answer."</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 输出</span>
<span class="token comment">// regex = (\w+)\s\1\W(\w+), content: He said that that was the the correct answer.</span>
<span class="token comment">// [1th] start: 8, end: 21, group: that that was</span>
<span class="token comment">// [2th] start: 22, end: 37, group: the the correct</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>说明：</p>
<ul>
<li><code>(\w+)</code>：匹配一个或多个单词字符。</li>
<li><code>\s</code>：与空白字符匹配。</li>
<li><code>\1</code>：匹配第一个组，即(\w+)。</li>
<li><code>\W</code>：匹配包括空格和标点符号的一个非单词字符。 这样可以防止正则表达式模式匹配从第一个捕获组的单词开头的单词。</li>
</ul>
<h4 id="命名的反向引用"><a href="#命名的反向引用" class="headerlink" title="命名的反向引用"></a>命名的反向引用</h4><p>命名后向引用通过使用下面的语法进行定义：<code>\k&lt;name &gt;</code></p>
<p><strong>【示例】匹配重复的单词和紧随每个重复的单词的单词(命名子表达式)</strong></p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// (?&lt;duplicateWord&gt;\w+)\s\k&lt;duplicateWord&gt;\W(?&lt;nextWord&gt;\w+) 匹配重复的单词和紧随每个重复的单词的单词</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"(?&lt;duplicateWord&gt;\\w+)\\s\\k&lt;duplicateWord&gt;\\W(?&lt;nextWord&gt;\\w+)"</span><span class="token punctuation">,</span>
		<span class="token string">"He said that that was the the correct answer."</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 输出</span>
<span class="token comment">// regex = (?&lt;duplicateWord&gt;\w+)\s\k&lt;duplicateWord&gt;\W(?&lt;nextWord&gt;\w+), content: He said that that was the the correct answer.</span>
<span class="token comment">// [1th] start: 8, end: 21, group: that that was</span>
<span class="token comment">// [2th] start: 22, end: 37, group: the the correct</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>说明：</p>
<ul>
<li><code>(?&lt;duplicateWord&gt;\w+)</code>：匹配一个或多个单词字符。 命名此捕获组 duplicateWord。</li>
<li><code>\s</code>: 与空白字符匹配。</li>
<li><code>\k&lt;duplicateWord&gt;</code>：匹配名为 duplicateWord 的捕获的组。</li>
<li><code>\W</code>：匹配包括空格和标点符号的一个非单词字符。 这样可以防止正则表达式模式匹配从第一个捕获组的单词开头的单词。</li>
<li><code>(?&lt;nextWord&gt;\w+)</code>：匹配一个或多个单词字符。 命名此捕获组 nextWord。</li>
</ul>
<h3 id="非捕获组"><a href="#非捕获组" class="headerlink" title="非捕获组"></a>非捕获组</h3><p><code>(?:exp)</code> 表示当一个限定符应用到一个组，但组捕获的子字符串并非所需时，通常会使用非捕获组构造。</p>
<p><strong>【示例】匹配以.结束的语句。</strong></p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// 匹配由句号终止的语句。</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"(?:\\b(?:\\w+)\\W*)+\\."</span><span class="token punctuation">,</span> <span class="token string">"This is a short sentence. Never end"</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 输出</span>
<span class="token comment">// regex = (?:\b(?:\w+)\W*)+\., content: This is a short sentence. Never end</span>
<span class="token comment">// [1th] start: 0, end: 25, group: This is a short sentence.</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<h3 id="零宽断言"><a href="#零宽断言" class="headerlink" title="零宽断言"></a>零宽断言</h3><p>用于查找在某些内容(但并不包括这些内容)之前或之后的东西，也就是说它们像\b,^,$那样用于指定一个位置，这个位置应该满足一定的条件(即断言)，因此它们也被称为零宽断言。</p>
<table>
<thead>
<tr>
<th>表达式</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td><code>(?=exp)</code></td>
<td>匹配 exp 前面的位置</td>
</tr>
<tr>
<td><code>(?&lt;=exp)</code></td>
<td>匹配 exp 后面的位置</td>
</tr>
<tr>
<td><code>(?!exp)</code></td>
<td>匹配后面跟的不是 exp 的位置</td>
</tr>
<tr>
<td><code>(?&lt;!exp)</code></td>
<td>匹配前面不是 exp 的位置</td>
</tr>
</tbody></table>
<h4 id="匹配-exp-前面的位置"><a href="#匹配-exp-前面的位置" class="headerlink" title="匹配 exp 前面的位置"></a>匹配 exp 前面的位置</h4><p><code>(?=exp)</code> 表示输入字符串必须匹配<em>子表达式</em>中的正则表达式模式，尽管匹配的子字符串未包含在匹配结果中。</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// \b\w+(?=\sis\b) 表示要捕获is之前的单词</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"\\b\\w+(?=\\sis\\b)"</span><span class="token punctuation">,</span> <span class="token string">"The dog is a Malamute."</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"\\b\\w+(?=\\sis\\b)"</span><span class="token punctuation">,</span> <span class="token string">"The island has beautiful birds."</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"\\b\\w+(?=\\sis\\b)"</span><span class="token punctuation">,</span> <span class="token string">"The pitch missed home plate."</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"\\b\\w+(?=\\sis\\b)"</span><span class="token punctuation">,</span> <span class="token string">"Sunday is a weekend day."</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 输出</span>
<span class="token comment">// regex = \b\w+(?=\sis\b), content: The dog is a Malamute.</span>
<span class="token comment">// [1th] start: 4, end: 7, group: dog</span>
<span class="token comment">// regex = \b\w+(?=\sis\b), content: The island has beautiful birds.</span>
<span class="token comment">// not found</span>
<span class="token comment">// regex = \b\w+(?=\sis\b), content: The pitch missed home plate.</span>
<span class="token comment">// not found</span>
<span class="token comment">// regex = \b\w+(?=\sis\b), content: Sunday is a weekend day.</span>
<span class="token comment">// [1th] start: 0, end: 6, group: Sunday</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>说明：</p>
<ul>
<li><code>\b</code>：在单词边界处开始匹配。</li>
<li><code>\w+</code>：匹配一个或多个单词字符。</li>
<li><code>(?=\sis\b)</code>：确定单词字符是否后接空白字符和字符串“is”，其在单词边界处结束。 如果如此，则匹配成功。</li>
</ul>
<h4 id="匹配-exp-后面的位置"><a href="#匹配-exp-后面的位置" class="headerlink" title="匹配 exp 后面的位置"></a>匹配 exp 后面的位置</h4><p><code>(?&lt;=exp)</code> 表示子表达式不得在输入字符串当前位置左侧出现，尽管子表达式未包含在匹配结果中。零宽度正回顾后发断言不会回溯。</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// (?&lt;=\b20)\d{2}\b 表示要捕获以20开头的数字的后面部分</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"(?&lt;=\\b20)\\d{2}\\b"</span><span class="token punctuation">,</span> <span class="token string">"2010 1999 1861 2140 2009"</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 输出</span>
<span class="token comment">// regex = (?&lt;=\b20)\d{2}\b, content: 2010 1999 1861 2140 2009</span>
<span class="token comment">// [1th] start: 2, end: 4, group: 10</span>
<span class="token comment">// [2th] start: 22, end: 24, group: 09</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>说明：</p>
<ul>
<li><code>\d{2}</code>：匹配两个十进制数字。</li>
<li><code>{?&lt;=\b20)</code>：如果两个十进制数字的字边界以小数位数“20”开头，则继续匹配。</li>
<li><code>\b</code>：在单词边界处结束匹配。</li>
</ul>
<h4 id="匹配后面跟的不是-exp-的位置"><a href="#匹配后面跟的不是-exp-的位置" class="headerlink" title="匹配后面跟的不是 exp 的位置"></a>匹配后面跟的不是 exp 的位置</h4><p><code>(?!exp)</code> 表示输入字符串不得匹配<em>子表达式</em>中的正则表达式模式，尽管匹配的子字符串未包含在匹配结果中。</p>
<p>【示例】捕获未以“un”开头的单词</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// \b(?!un)\w+\b 表示要捕获未以“un”开头的单词</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"\\b(?!un)\\w+\\b"</span><span class="token punctuation">,</span> <span class="token string">"unite one unethical ethics use untie ultimate"</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 输出</span>
<span class="token comment">// regex = \b(?!un)\w+\b, content: unite one unethical ethics use untie ultimate</span>
<span class="token comment">// [1th] start: 6, end: 9, group: one</span>
<span class="token comment">// [2th] start: 20, end: 26, group: ethics</span>
<span class="token comment">// [3th] start: 27, end: 30, group: use</span>
<span class="token comment">// [4th] start: 37, end: 45, group: ultimate</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>说明：</p>
<ul>
<li><code>\b</code>：在单词边界处开始匹配。</li>
<li><code>(?!un)</code>：确定接下来的两个的字符是否为“un”。 如果没有，则可能匹配。</li>
<li><code>\w+</code>：匹配一个或多个单词字符。</li>
<li><code>\b</code>：在单词边界处结束匹配。</li>
</ul>
<h4 id="匹配前面不是-exp-的位置"><a href="#匹配前面不是-exp-的位置" class="headerlink" title="匹配前面不是 exp 的位置"></a>匹配前面不是 exp 的位置</h4><p><code>(?&lt;!exp)</code> 表示子表达式不得在输入字符串当前位置的左侧出现。 但是，任何不匹配子表达式 的子字符串不包含在匹配结果中。</p>
<p>【示例】捕获任意工作日</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// (?&lt;!(Saturday|Sunday) )\b\w+ \d{1,2}, \d{4}\b 表示要捕获任意工作日（即周一到周五）</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"(?&lt;!(Saturday|Sunday) )\\b\\w+ \\d{1,2}, \\d{4}\\b"</span><span class="token punctuation">,</span> <span class="token string">"Monday February 1, 2010"</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"(?&lt;!(Saturday|Sunday) )\\b\\w+ \\d{1,2}, \\d{4}\\b"</span><span class="token punctuation">,</span> <span class="token string">"Wednesday February 3, 2010"</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"(?&lt;!(Saturday|Sunday) )\\b\\w+ \\d{1,2}, \\d{4}\\b"</span><span class="token punctuation">,</span> <span class="token string">"Saturday February 6, 2010"</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertFalse</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"(?&lt;!(Saturday|Sunday) )\\b\\w+ \\d{1,2}, \\d{4}\\b"</span><span class="token punctuation">,</span> <span class="token string">"Sunday February 7, 2010"</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"(?&lt;!(Saturday|Sunday) )\\b\\w+ \\d{1,2}, \\d{4}\\b"</span><span class="token punctuation">,</span> <span class="token string">"Monday, February 8, 2010"</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 输出</span>
<span class="token comment">// regex = (?&lt;!(Saturday|Sunday) )\b\w+ \d{1,2}, \d{4}\b, content: Monday February 1, 2010</span>
<span class="token comment">// [1th] start: 7, end: 23, group: February 1, 2010</span>
<span class="token comment">// regex = (?&lt;!(Saturday|Sunday) )\b\w+ \d{1,2}, \d{4}\b, content: Wednesday February 3, 2010</span>
<span class="token comment">// [1th] start: 10, end: 26, group: February 3, 2010</span>
<span class="token comment">// regex = (?&lt;!(Saturday|Sunday) )\b\w+ \d{1,2}, \d{4}\b, content: Saturday February 6, 2010</span>
<span class="token comment">// not found</span>
<span class="token comment">// regex = (?&lt;!(Saturday|Sunday) )\b\w+ \d{1,2}, \d{4}\b, content: Sunday February 7, 2010</span>
<span class="token comment">// not found</span>
<span class="token comment">// regex = (?&lt;!(Saturday|Sunday) )\b\w+ \d{1,2}, \d{4}\b, content: Monday, February 8, 2010</span>
<span class="token comment">// [1th] start: 8, end: 24, group: February 8, 2010</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<h2 id="贪婪与懒惰"><a href="#贪婪与懒惰" class="headerlink" title="贪婪与懒惰"></a>贪婪与懒惰</h2><p>当正则表达式中包含能接受重复的限定符时，通常的行为是（在使整个表达式能得到匹配的前提下）匹配<strong>尽可能多</strong>的字符。以这个表达式为例：a.*b，它将会匹配最长的以 a 开始，以 b 结束的字符串。如果用它来搜索 aabab 的话，它会匹配整个字符串 aabab。这被称为贪婪匹配。</p>
<p>有时，我们更需要懒惰匹配，也就是匹配<strong>尽可能少</strong>的字符。前面给出的限定符都可以被转化为懒惰匹配模式，只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复，但是在能使整个匹配成功的前提下使用最少的重复。</p>
<table>
<thead>
<tr>
<th>表达式</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td><code>*?</code></td>
<td>重复任意次，但尽可能少重复</td>
</tr>
<tr>
<td><code>+?</code></td>
<td>重复 1 次或更多次，但尽可能少重复</td>
</tr>
<tr>
<td><code>??</code></td>
<td>重复 0 次或 1 次，但尽可能少重复</td>
</tr>
<tr>
<td><code>{n,m}?</code></td>
<td>重复 n 到 m 次，但尽可能少重复</td>
</tr>
<tr>
<td><code>{n,}?</code></td>
<td>重复 n 次以上，但尽可能少重复</td>
</tr>
</tbody></table>
<p>【示例】Java 正则中贪婪与懒惰的示例</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// 贪婪匹配</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"a\\w*b"</span><span class="token punctuation">,</span> <span class="token string">"abaabaaabaaaab"</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 懒惰匹配</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"a\\w*?b"</span><span class="token punctuation">,</span> <span class="token string">"abaabaaabaaaab"</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"a\\w+?b"</span><span class="token punctuation">,</span> <span class="token string">"abaabaaabaaaab"</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"a\\w??b"</span><span class="token punctuation">,</span> <span class="token string">"abaabaaabaaaab"</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"a\\w{0,4}?b"</span><span class="token punctuation">,</span> <span class="token string">"abaabaaabaaaab"</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token string">"a\\w{3,}?b"</span><span class="token punctuation">,</span> <span class="token string">"abaabaaabaaaab"</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 输出</span>
<span class="token comment">// regex = a\w*b, content: abaabaaabaaaab</span>
<span class="token comment">// [1th] start: 0, end: 14, group: abaabaaabaaaab</span>
<span class="token comment">// regex = a\w*?b, content: abaabaaabaaaab</span>
<span class="token comment">// [1th] start: 0, end: 2, group: ab</span>
<span class="token comment">// [2th] start: 2, end: 5, group: aab</span>
<span class="token comment">// [3th] start: 5, end: 9, group: aaab</span>
<span class="token comment">// [4th] start: 9, end: 14, group: aaaab</span>
<span class="token comment">// regex = a\w+?b, content: abaabaaabaaaab</span>
<span class="token comment">// [1th] start: 0, end: 5, group: abaab</span>
<span class="token comment">// [2th] start: 5, end: 9, group: aaab</span>
<span class="token comment">// [3th] start: 9, end: 14, group: aaaab</span>
<span class="token comment">// regex = a\w??b, content: abaabaaabaaaab</span>
<span class="token comment">// [1th] start: 0, end: 2, group: ab</span>
<span class="token comment">// [2th] start: 2, end: 5, group: aab</span>
<span class="token comment">// [3th] start: 6, end: 9, group: aab</span>
<span class="token comment">// [4th] start: 11, end: 14, group: aab</span>
<span class="token comment">// regex = a\w{0,4}?b, content: abaabaaabaaaab</span>
<span class="token comment">// [1th] start: 0, end: 2, group: ab</span>
<span class="token comment">// [2th] start: 2, end: 5, group: aab</span>
<span class="token comment">// [3th] start: 5, end: 9, group: aaab</span>
<span class="token comment">// [4th] start: 9, end: 14, group: aaaab</span>
<span class="token comment">// regex = a\w{3,}?b, content: abaabaaabaaaab</span>
<span class="token comment">// [1th] start: 0, end: 5, group: abaab</span>
<span class="token comment">// [2th] start: 5, end: 14, group: aaabaaaab</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>说明：</p>
<p>本例中代码展示的是使用不同贪婪或懒惰策略去查找字符串 <code>abaabaaabaaaab</code> 中匹配<strong>以 <code>a</code> 开头，以 <code>b</code> 结尾的所有子字符串</strong>。请从输出结果中，细细体味使用不同的贪婪或懒惰策略，对于匹配子字符串有什么影响。</p>
<h2 id="正则附录"><a href="#正则附录" class="headerlink" title="正则附录"></a>正则附录</h2><h3 id="匹配正则字符串的方法"><a href="#匹配正则字符串的方法" class="headerlink" title="匹配正则字符串的方法"></a>匹配正则字符串的方法</h3><p>由于正则表达式中很多元字符本身就是转义字符，在 Java 字符串的规则中不会被显示出来。</p>
<p>为此，可以使用一个工具类<code>org.apache.commons.lang3.StringEscapeUtils</code>来做特殊处理，使得转义字符可以打印。这个工具类提供的都是静态方法，从方法命名大致也可以猜出用法，这里不多做说明。</p>
<p>如果你了解 maven，可以直接引入依赖</p>
<pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.apache.commons<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>commons-lang3<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>${commons-lang3.version}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>【示例】本文为了展示正则匹配规则用到的方法</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">boolean</span> <span class="token function">checkMatches</span><span class="token punctuation">(</span><span class="token class-name">String</span> regex<span class="token punctuation">,</span> <span class="token class-name">String</span> content<span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token class-name">Pattern</span> p <span class="token operator">=</span> <span class="token class-name">Pattern</span><span class="token punctuation">.</span><span class="token function">compile</span><span class="token punctuation">(</span>regex<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">Matcher</span> m <span class="token operator">=</span> p<span class="token punctuation">.</span><span class="token function">matcher</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">boolean</span> flag <span class="token operator">=</span> m<span class="token punctuation">.</span><span class="token function">matches</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>m<span class="token punctuation">.</span><span class="token function">matches</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">StringEscapeUtils</span><span class="token punctuation">.</span><span class="token function">escapeJava</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"\tmatches： "</span> <span class="token operator">+</span> <span class="token class-name">StringEscapeUtils</span><span class="token punctuation">.</span><span class="token function">escapeJava</span><span class="token punctuation">(</span>regex<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">StringEscapeUtils</span><span class="token punctuation">.</span><span class="token function">escapeJava</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"\tnot matches： "</span> <span class="token operator">+</span> <span class="token class-name">StringEscapeUtils</span><span class="token punctuation">.</span><span class="token function">escapeJava</span><span class="token punctuation">(</span>regex<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">return</span> flag<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">findAll</span><span class="token punctuation">(</span><span class="token class-name">String</span> regex<span class="token punctuation">,</span> <span class="token class-name">String</span> content<span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token class-name">Pattern</span> p <span class="token operator">=</span> <span class="token class-name">Pattern</span><span class="token punctuation">.</span><span class="token function">compile</span><span class="token punctuation">(</span>regex<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">Matcher</span> m <span class="token operator">=</span> p<span class="token punctuation">.</span><span class="token function">matcher</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"regex = "</span> <span class="token operator">+</span> regex <span class="token operator">+</span> <span class="token string">", content: "</span> <span class="token operator">+</span> content<span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token keyword">int</span> count <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
	<span class="token keyword">while</span> <span class="token punctuation">(</span>m<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		count<span class="token operator">++</span><span class="token punctuation">;</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"["</span> <span class="token operator">+</span> count <span class="token operator">+</span> <span class="token string">"th] "</span> <span class="token operator">+</span> <span class="token string">"start: "</span> <span class="token operator">+</span> m<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">", end: "</span> <span class="token operator">+</span> m<span class="token punctuation">.</span><span class="token function">end</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
				<span class="token operator">+</span> <span class="token string">", group: "</span> <span class="token operator">+</span> m<span class="token punctuation">.</span><span class="token function">group</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token number">0</span> <span class="token operator">==</span> count<span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"not found"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">return</span> count<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<h3 id="速查元字符字典"><a href="#速查元字符字典" class="headerlink" title="速查元字符字典"></a>速查元字符字典</h3><p>为了方便快查正则的元字符含义，在本节根据元字符的功能集中罗列正则的各种元字符。</p>
<h4 id="限定符"><a href="#限定符" class="headerlink" title="限定符"></a>限定符</h4><table>
<thead>
<tr>
<th>字符</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td><code>*</code></td>
<td>匹配前面的子表达式零次或多次。例如，zo* 能匹配 “z” 以及 “zoo”。* 等价于{0,}。</td>
</tr>
<tr>
<td><code>+</code></td>
<td>匹配前面的子表达式一次或多次。例如，’zo+’ 能匹配 “zo” 以及 “zoo”，但不能匹配 “z”。+ 等价于 {1,}。</td>
</tr>
<tr>
<td><code>?</code></td>
<td>匹配前面的子表达式零次或一次。例如，”do(es)?” 可以匹配 “do” 或 “does” 中的”do” 。? 等价于 {0,1}。</td>
</tr>
<tr>
<td><code>{n}</code></td>
<td>n 是一个非负整数。匹配确定的 n 次。例如，’o{2}’ 不能匹配 “Bob” 中的 ‘o’，但是能匹配 “food” 中的两个 o。</td>
</tr>
<tr>
<td><code>{n,}</code></td>
<td>n 是一个非负整数。至少匹配 n 次。例如，’o{2,}’ 不能匹配 “Bob” 中的 ‘o’，但能匹配 “foooood” 中的所有 o。’o{1,}’ 等价于 ‘o+’。’o{0,}’ 则等价于 ‘o*‘。</td>
</tr>
<tr>
<td><code>{n,m}</code></td>
<td>m 和 n 均为非负整数，其中 n &lt;= m。最少匹配 n 次且最多匹配 m 次。例如，”o{1,3}” 将匹配 “fooooood” 中的前三个 o。’o{0,1}’ 等价于 ‘o?’。请注意在逗号和两个数之间不能有空格。</td>
</tr>
</tbody></table>
<h4 id="定位符"><a href="#定位符" class="headerlink" title="定位符"></a>定位符</h4><table>
<thead>
<tr>
<th>字符</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td><code>^</code></td>
<td>匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性，^ 还会与 \n 或 \r 之后的位置匹配。</td>
</tr>
<tr>
<td><code>$</code></td>
<td>匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性，$ 还会与 \n 或 \r 之前的位置匹配。</td>
</tr>
<tr>
<td><code>\b</code></td>
<td>匹配一个字边界，即字与空格间的位置。</td>
</tr>
<tr>
<td><code>\B</code></td>
<td>非字边界匹配。</td>
</tr>
</tbody></table>
<h4 id="非打印字符"><a href="#非打印字符" class="headerlink" title="非打印字符"></a>非打印字符</h4><table>
<thead>
<tr>
<th>字符</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td><code>\cx</code></td>
<td>匹配由 x 指明的控制字符。例如， \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则，将 c 视为一个原义的 ‘c’ 字符。</td>
</tr>
<tr>
<td><code>\f</code></td>
<td>匹配一个换页符。等价于 \x0c 和 \cL。</td>
</tr>
<tr>
<td><code>\n</code></td>
<td>匹配一个换行符。等价于 \x0a 和 \cJ。</td>
</tr>
<tr>
<td><code>\r</code></td>
<td>匹配一个回车符。等价于 \x0d 和 \cM。</td>
</tr>
<tr>
<td><code>\s</code></td>
<td>匹配任何空白字符，包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。</td>
</tr>
<tr>
<td><code>\S</code></td>
<td>匹配任何非空白字符。等价于 [ \f\n\r\t\v]。</td>
</tr>
<tr>
<td><code>\t</code></td>
<td>匹配一个制表符。等价于 \x09 和 \cI。</td>
</tr>
<tr>
<td><code>\v</code></td>
<td>匹配一个垂直制表符。等价于 \x0b 和 \cK。</td>
</tr>
</tbody></table>
<h4 id="分组"><a href="#分组" class="headerlink" title="分组"></a>分组</h4><table>
<thead>
<tr>
<th>表达式</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td><code>(exp)</code></td>
<td>匹配的子表达式。()中的内容就是子表达式。</td>
</tr>
<tr>
<td><code>(?&lt;name&gt;exp)</code></td>
<td>命名的子表达式（反向引用）。</td>
</tr>
<tr>
<td><code>(?:exp)</code></td>
<td>非捕获组，表示当一个限定符应用到一个组，但组捕获的子字符串并非所需时，通常会使用非捕获组构造。</td>
</tr>
<tr>
<td><code>(?=exp)</code></td>
<td>匹配 exp 前面的位置。</td>
</tr>
<tr>
<td><code>(?&lt;=exp)</code></td>
<td>匹配 exp 后面的位置。</td>
</tr>
<tr>
<td><code>(?!exp)</code></td>
<td>匹配后面跟的不是 exp 的位置。</td>
</tr>
<tr>
<td><code>(?&lt;!exp)</code></td>
<td>匹配前面不是 exp 的位置。</td>
</tr>
</tbody></table>
<h4 id="特殊符号"><a href="#特殊符号" class="headerlink" title="特殊符号"></a>特殊符号</h4><table>
<thead>
<tr>
<th>字符</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td><code>\</code></td>
<td>将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如， ‘n’ 匹配字符 ‘n’。’\n’ 匹配换行符。序列 ‘\‘ 匹配 “"，而 ‘(‘ 则匹配 “(“。</td>
</tr>
<tr>
<td><code>|</code></td>
<td>指明两项之间的一个选择。</td>
</tr>
<tr>
<td><code>[]</code></td>
<td>匹配方括号范围内的任意一个字符。形式如：[xyz]、[^xyz]、[a-z]、[^a-z]、[x,y,z]</td>
</tr>
</tbody></table>
<h2 id="正则实战"><a href="#正则实战" class="headerlink" title="正则实战"></a>正则实战</h2><p>虽然本系列洋洋洒洒的大谈特谈正则表达式。但是我还是要在这里建议，如果一个正则表达式没有经过充分测试，还是要谨慎使用。</p>
<p>正则是把双刃剑，它可以为你节省大量的代码行。但是由于它不易阅读，维护起来可是头疼的哦（你需要一个字符一个字符的去理解）。</p>
<h3 id="最实用的正则"><a href="#最实用的正则" class="headerlink" title="最实用的正则"></a>最实用的正则</h3><h4 id="校验中文"><a href="#校验中文" class="headerlink" title="校验中文"></a>校验中文</h4><p>校验字符串中只能有中文字符（不包括中文标点符号）。中文字符的 Unicode 编码范围是 <code>\u4e00</code> 到 <code>\u9fa5</code>。</p>
<blockquote>
<p>如有兴趣，可以参考<a target="_blank" rel="noopener" href="http://baike.baidu.com/link?url=3xi0vmvCIGKQLJZdn_BYhQ1IDFsoSJMrya6_eOjCBb7A6cRIW-zhZFLC9Yh8wjxU6A_HCfNuP8FBBXU9CN3Wcq"><strong>百度百科-Unicode</strong></a> 。</p>
</blockquote>
<pre class="line-numbers language-none"><code class="language-none">^[\u4e00-\u9fa5]+$<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<ul>
<li><strong>匹配：</strong> 春眠不觉晓</li>
<li><strong>不匹配：</strong>春眠不觉晓，</li>
</ul>
<h4 id="校验身份证号码"><a href="#校验身份证号码" class="headerlink" title="校验身份证号码"></a>校验身份证号码</h4><p>身份证为 15 位或 18 位。15 位是第一代身份证。从 1999 年 10 月 1 日起，全国实行公民身份证号码制度，居民身份证编号由原 15 位升至 18 位。</p>
<ul>
<li><strong>15 位身份证</strong>：由 15 位数字组成。排列顺序从左至右依次为：六位数字地区码；六位数字出生日期；三位顺序号，其中 15 位男为单数，女为双数。</li>
<li><strong>18 位身份证</strong>：由十七位数字本体码和一位数字校验码组成。排列顺序从左至右依次为：六位数字地区码；八位数字出生日期；三位数字顺序码和一位数字校验码（也可能是 X）。</li>
</ul>
<blockquote>
<p>身份证号含义详情请见：<a target="_blank" rel="noopener" href="http://baike.baidu.com/link?url=5mYlYNE0RsSe2D4tydajtiaR8hAm4pPZ0FHSPuQ05N4f6H-i7qPuw7sY5KfNuiOVJWVWZvU4gf3IY-vIcKdP1CU4Fv-9pKmFQB50qGv_hZT2dkGbkd9--8_saY7omV80vEw9ixVeEwda37fHswfmtyU4QSiBG5s3K5K-JnYr1dqNlPu0f3t008UcLh5-wyID"><strong>百度百科-居民身份证号码</strong></a></p>
</blockquote>
<p><strong>地区码（6 位）</strong></p>
<pre class="line-numbers language-none"><code class="language-none">(1[1-5]|2[1-3]|3[1-7]|4[1-3]|5[0-4]|6[1-5])\d{4}<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<p><strong>出生日期（8 位）</strong></p>
<p>注：下面的是 18 位身份证的有效出生日期，如果是 15 位身份证，只要将第一个\d{4}改为\d{2}即可。</p>
<pre class="line-numbers language-none"><code class="language-none">((\d{4}((0[13578]|1[02])(0[1-9]|[12]\d|3[01])|(0[13456789]|1[012])(0[1-9]|[12]\d|30)|02(0[1-9]|1\d|2[0-8])))|([02468][048]|[13579][26])0229)<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<p><strong>15 位有效身份证</strong></p>
<pre class="line-numbers language-none"><code class="language-none">^((1[1-5]|2[1-3]|3[1-7]|4[1-3]|5[0-4]|6[1-5])\d{4})((\d{2}((0[13578]|1[02])(0[1-9]|[12]\d|3[01])|(0[13456789]|1[012])(0[1-9]|[12]\d|30)|02(0[1-9]|1\d|2[0-8])))|([02468][048]|[13579][26])0229)(\d{3})$<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<ul>
<li><p><strong>匹配：</strong>110001700101031</p>
</li>
<li><p><strong>不匹配：</strong>110001701501031</p>
</li>
</ul>
<p><strong>18 位有效身份证</strong></p>
<pre class="line-numbers language-none"><code class="language-none">^((1[1-5]|2[1-3]|3[1-7]|4[1-3]|5[0-4]|6[1-5])\d{4})((\d{4}((0[13578]|1[02])(0[1-9]|[12]\d|3[01])|(0[13456789]|1[012])(0[1-9]|[12]\d|30)|02(0[1-9]|1\d|2[0-8])))|([02468][048]|[13579][26])0229)(\d{3}(\d|X))$<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<ul>
<li><p><strong>匹配：</strong>110001199001010310 | 11000019900101015X</p>
</li>
<li><p><strong>不匹配：</strong>990000199001010310 | 110001199013010310</p>
</li>
</ul>
<h4 id="校验有效用户名、密码"><a href="#校验有效用户名、密码" class="headerlink" title="校验有效用户名、密码"></a>校验有效用户名、密码</h4><p><strong>描述：</strong>长度为 6-18 个字符，允许输入字母、数字、下划线，首字符必须为字母。</p>
<pre class="line-numbers language-none"><code class="language-none">^[a-zA-Z]\w{5,17}$<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<ul>
<li><p><strong>匹配：</strong><a href="mailto:he_llo@worl.d.com">he_llo@worl.d.com</a> | <a href="mailto:hel.l-o@wor-ld.museum">hel.l-o@wor-ld.museum</a> | <a href="mailto:h1ello@123.com">h1ello@123.com</a></p>
</li>
<li><p><strong>不匹配：</strong><a href="mailto:hello@worl_d.com">hello@worl_d.com</a> | he&amp;<a href="mailto:llo@world.co1">llo@world.co1</a> | .hello@wor#.co.uk</p>
</li>
</ul>
<h4 id="校验邮箱"><a href="#校验邮箱" class="headerlink" title="校验邮箱"></a>校验邮箱</h4><p><strong>描述：</strong>不允许使用 IP 作为域名，如 : <a href="mailto:hello@154.145.68.12">hello@154.145.68.12</a></p>
<p><code>@</code>符号前的邮箱用户和<code>.</code>符号前的域名(domain)必须满足以下条件：</p>
<ul>
<li>字符只能是英文字母、数字、下划线<code>_</code>、<code>.</code>、<code>-</code> ；</li>
<li>首字符必须为字母或数字；</li>
<li><code>_</code>、<code>.</code>、<code>-</code> 不能连续出现。</li>
</ul>
<p>域名的根域只能为字母，且至少为两个字符。</p>
<pre class="line-numbers language-none"><code class="language-none">^[A-Za-z0-9](([_\.\-]?[a-zA-Z0-9]+)*)@([A-Za-z0-9]+)(([\.\-]?[a-zA-Z0-9]+)*)\.([A-Za-z]{2,})$<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<ul>
<li><strong>匹配：</strong><a href="mailto:he_llo@worl.d.com">he_llo@worl.d.com</a> | <a href="mailto:hel.l-o@wor-ld.museum">hel.l-o@wor-ld.museum</a> | <a href="mailto:h1ello@123.com">h1ello@123.com</a></li>
<li><strong>不匹配：</strong><a href="mailto:hello@worl_d.com">hello@worl_d.com</a> | he&amp;<a href="mailto:llo@world.co1">llo@world.co1</a> | .hello@wor#.co.uk</li>
</ul>
<h4 id="校验-URL"><a href="#校验-URL" class="headerlink" title="校验 URL"></a>校验 URL</h4><p><strong>描述：</strong>校验 URL。支持 http、https、ftp、ftps。</p>
<pre class="line-numbers language-none"><code class="language-none">^(ht|f)(tp|tps)\://[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3})?(/\S*)?$<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<ul>
<li><p><strong>匹配：</strong><a target="_blank" rel="noopener" href="http://google.com/help/me">http://google.com/help/me</a> | <a target="_blank" rel="noopener" href="http://www.google.com/help/me/">http://www.google.com/help/me/</a> | <a target="_blank" rel="noopener" href="https://www.google.com/help.asp">https://www.google.com/help.asp</a> | <a href="ftp://www.google.com/">ftp://www.google.com</a> | ftps://google.org</p>
</li>
<li><p><strong>不匹配：</strong><a target="_blank" rel="noopener" href="http://un/www.google.com/index.asp">http://un/www.google.com/index.asp</a></p>
</li>
</ul>
<h4 id="校验时间"><a href="#校验时间" class="headerlink" title="校验时间"></a>校验时间</h4><p><strong>描述：</strong>校验时间。时、分、秒必须是有效数字，如果数值不是两位数，十位需要补零。</p>
<pre class="line-numbers language-none"><code class="language-none">^([0-1][0-9]|[2][0-3]):([0-5][0-9])$<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<ul>
<li><p><strong>匹配：</strong>00:00:00 | 23:59:59 | 17:06:30</p>
</li>
<li><p><strong>不匹配：</strong>17:6:30 | 24:16:30</p>
</li>
</ul>
<h4 id="校验日期"><a href="#校验日期" class="headerlink" title="校验日期"></a>校验日期</h4><p><strong>描述：</strong>校验日期。日期满足以下条件：</p>
<ul>
<li>格式 yyyy-MM-dd 或 yyyy-M-d</li>
<li>连字符可以没有或是“-”、“/”、“.”之一</li>
<li>闰年的二月可以有 29 日；而平年不可以。</li>
<li>一、三、五、七、八、十、十二月为 31 日。四、六、九、十一月为 30 日。</li>
</ul>
<pre class="line-numbers language-none"><code class="language-none">^(?:(?!0000)[0-9]{4}([-/.]?)(?:(?:0?[1-9]|1[0-2])\1(?:0?[1-9]|1[0-9]|2[0-8])|(?:0?[13-9]|1[0-2])\1(?:29|30)|(?:0?[13578]|1[02])\1(?:31))|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)([-/.]?)0?2\2(?:29))$<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<ul>
<li><strong>匹配：</strong>2016/1/1 | 2016/01/01 | 20160101 | 2016-01-01 | 2016.01.01 | 2000-02-29</li>
<li><strong>不匹配：</strong>2001-02-29 | 2016/12/32 | 2016/6/31 | 2016/13/1 | 2016/0/1</li>
</ul>
<h4 id="校验中国手机号码"><a href="#校验中国手机号码" class="headerlink" title="校验中国手机号码"></a>校验中国手机号码</h4><p><strong>描述：</strong>中国手机号码正确格式：11 位数字。</p>
<blockquote>
<p>移动有 16 个号段：134、135、136、137、138、139、147、150、151、152、157、158、159、182、187、188。其中 147、157、188 是 3G 号段，其他都是 2G 号段。联通有 7 种号段：130、131、132、155、156、185、186。其中 186 是 3G（WCDMA）号段，其余为 2G 号段。电信有 4 个号段：133、153、180、189。其中 189 是 3G 号段（CDMA2000），133 号段主要用作无线网卡号。总结：13 开头手机号 0-9；15 开头手机号 0-3、5-9；18 开头手机号 0、2、5-9。</p>
<p>此外，中国在国际上的区号为 86，所以手机号开头有+86、86 也是合法的。</p>
<p>以上信息来源于 <a target="_blank" rel="noopener" href="http://baike.baidu.com/link?url=Bia2K_f8rGcakOlP4d9m_-DNSgXU5-0NDP0pPavS0ZbhRHQcUFUTbMERjdO4u7cvkpTJaIDeUXq_EXWnMqXMdSuMQDX3NAbZXAlZYl_V18KATWF7y1EFzUyJ62rf3bAN"><strong>百度百科-手机号</strong></a></p>
</blockquote>
<pre class="line-numbers language-none"><code class="language-none">^((\+)?86\s*)?((13[0-9])|(15([0-3]|[5-9]))|(18[0,2,5-9]))\d{8}$<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<ul>
<li><p><strong>匹配：</strong>+86 18012345678 | 86 18012345678 | 15812345678</p>
</li>
<li><p><strong>不匹配：</strong>15412345678 | 12912345678 | 180123456789</p>
</li>
</ul>
<h4 id="校验中国固话号码"><a href="#校验中国固话号码" class="headerlink" title="校验中国固话号码"></a>校验中国固话号码</h4><p><strong>描述：</strong>固话号码，必须加区号（以 0 开头）。<br>3 位有效区号：010、020~029，固话位数为 8 位。<br>4 位有效区号：03xx 开头到 09xx，固话位数为 7。</p>
<blockquote>
<p>如果想了解更详细的信息，请参考 <a target="_blank" rel="noopener" href="http://baike.baidu.com/link?url=sX8JoxK1ja5uM5pDYvQe27_QsyqAZ_78DLSeEvwjqtG_uXqU6p5Oh7CPbImNbnwu1ClOmD8udgDIswZfYzQIw0z3BYZO3eTplvVDzieuowTYqt7yHGDAqyT7o4vvGhg4"><strong>百度百科-电话区号</strong></a> 。</p>
</blockquote>
<pre class="line-numbers language-none"><code class="language-none">^(010|02[0-9])(\s|-)\d{8}|(0[3-9]\d{2})(\s|-)\d{7}$<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<ul>
<li><p><strong>匹配：</strong>010-12345678 | 010 12345678 | 0512-1234567 | 0512 1234567</p>
</li>
<li><p><strong>不匹配：</strong>1234567 | 12345678</p>
</li>
</ul>
<h4 id="校验-IPv4-地址"><a href="#校验-IPv4-地址" class="headerlink" title="校验 IPv4 地址"></a>校验 IPv4 地址</h4><p><strong>描述：</strong>IP 地址是一个 32 位的二进制数，通常被分割为 4 个“8 位二进制数”（也就是 4 个字节）。IP 地址通常用“点分十进制”表示成（a.b.c.d）的形式，其中，a,b,c,d 都是 0~255 之间的十进制整数。</p>
<pre class="line-numbers language-none"><code class="language-none">^([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])$<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<ul>
<li><p><strong>匹配：</strong>0.0.0.0 | 255.255.255.255 | 127.0.0.1</p>
</li>
<li><p><strong>不匹配：</strong>10.10.10 | 10.10.10.256</p>
</li>
</ul>
<h4 id="校验-IPv6-地址"><a href="#校验-IPv6-地址" class="headerlink" title="校验 IPv6 地址"></a>校验 IPv6 地址</h4><p><strong>描述：</strong>IPv6 的 128 位地址通常写成 8 组，每组为四个十六进制数的形式。</p>
<p>IPv6 地址可以表示为以下形式：</p>
<ul>
<li>IPv6 地址</li>
<li>零压缩 IPv6 地址(<a target="_blank" rel="noopener" href="https://tools.ietf.org/html/rfc5952#section-2.2">section 2.2 of rfc5952</a>)</li>
<li>带有本地链接区域索引的 IPv6 地址 (<a target="_blank" rel="noopener" href="https://tools.ietf.org/html/rfc4007#section-11">section 11 of rfc4007</a>)</li>
<li>嵌入 IPv4 的 IPv6 地址(<a target="_blank" rel="noopener" href="https://tools.ietf.org/html/rfc6052#section-2">section 2 of rfc6052</a></li>
<li>映射 IPv4 的 IPv6 地址 (<a target="_blank" rel="noopener" href="https://tools.ietf.org/html/rfc2765#section-2.1">section 2.1 of rfc2765</a>)</li>
<li>翻译 IPv4 的 IPv6 地址 (<a target="_blank" rel="noopener" href="https://tools.ietf.org/html/rfc2765#section-2.1">section 2.1 of rfc2765</a>)</li>
</ul>
<blockquote>
<p>显然，IPv6 地址的表示方式很复杂。你也可以参考：</p>
<p><a target="_blank" rel="noopener" href="http://baike.baidu.com/link?url=D3nmh0q_G_ZVmxXFG79mjjNfT4hs9fwjqUgygh-tvhq43KYqx88HV27WEXmoT4nA4iGzXwXMm5L-j50C2gSL5q"><strong>百度百科-IPv6</strong></a></p>
<p><a target="_blank" rel="noopener" href="http://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses"><strong>Stack overflow 上的 IPv6 正则表达高票答案</strong></a></p>
</blockquote>
<pre class="line-numbers language-none"><code class="language-none">(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>

<ul>
<li><p><strong>匹配：</strong>1:2:3:4:5:6:7:8 | 1:: | 1::8 | 1::6:7:8 | 1::5:6:7:8 | 1::4:5:6:7:8 | 1::3:4:5:6:7:8 | ::2:3:4:5:6:7:8 | 1:2:3:4:5:6:7:: | 1:2:3:4:5:6::8 | 1:2:3:4:5::8 | 1:2:3:4::8 | 1:2:3::8 | 1:2::8 | 1::8 | ::8 | fe80::7:8%1 | ::255.255.255.255 | 2001:db8:3:4::192.0.2.33 | 64:ff9b::192.0.2.33</p>
</li>
<li><p><strong>不匹配：</strong>1.2.3.4.5.6.7.8 | 1::2::3</p>
</li>
</ul>
<h3 id="特定字符"><a href="#特定字符" class="headerlink" title="特定字符"></a>特定字符</h3><ul>
<li>匹配长度为 3 的字符串：<code>^.{3}$</code>。</li>
<li>匹配由 26 个英文字母组成的字符串：<code>^[A-Za-z]+$</code>。</li>
<li>匹配由 26 个大写英文字母组成的字符串：<code>^[A-Z]+$</code>。</li>
<li>匹配由 26 个小写英文字母组成的字符串：<code>^[a-z]+$</code>。</li>
<li>匹配由数字和 26 个英文字母组成的字符串：<code>^[A-Za-z0-9]+$</code>。</li>
<li>匹配由数字、26 个英文字母或者下划线组成的字符串：<code>^\w+$</code>。</li>
</ul>
<h3 id="特定数字"><a href="#特定数字" class="headerlink" title="特定数字"></a>特定数字</h3><ul>
<li>匹配正整数：<code>^[1-9]\d*$</code></li>
<li>匹配负整数：<code>^-[1-9]\d*$</code></li>
<li>匹配整数：<code>^(-?[1-9]\d*)|0$</code></li>
<li>匹配正浮点数：<code>^[1-9]\d*\.\d+|0\.\d+$</code></li>
<li>匹配负浮点数：<code>^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$</code></li>
<li>匹配浮点数：<code>^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$</code></li>
</ul>
<h2 id="正则表达式的性能"><a href="#正则表达式的性能" class="headerlink" title="正则表达式的性能"></a>正则表达式的性能</h2><p>目前实现正则表达式引擎的方式有两种：DFA 自动机（Deterministic Final Automata 确定有限状态自动机）和 NFA 自动机（Non deterministic Finite Automaton 非确定有限状态自动机）。对比来看，构造 DFA 自动机的代价远大于 NFA 自动机，但 DFA 自动机的执行效率高于 NFA 自动机。</p>
<p>假设一个字符串的长度是 n，如果用 DFA 自动机作为正则表达式引擎，则匹配的时间复杂度为 O(n)；如果用 NFA 自动机作为正则表达式引擎，由于 NFA 自动机在匹配过程中存在大量的分支和回溯，假设 NFA 的状态数为 s，则该匹配算法的时间复杂度为 O（ns）。</p>
<p>NFA 自动机的优势是支持更多功能。例如，捕获 group、环视、占有优先量词等高级功能。这些功能都是基于子表达式独立进行匹配，因此在编程语言里，使用的正则表达式库都是基于 NFA 实现的。</p>
<h3 id="NFA-自动机的回溯"><a href="#NFA-自动机的回溯" class="headerlink" title="NFA 自动机的回溯"></a>NFA 自动机的回溯</h3><p>用 NFA 自动机实现的比较复杂的正则表达式，在匹配过程中经常会引起回溯问题。大量的回溯会长时间地占用 CPU，从而带来系统性能开销。</p>
<pre class="line-numbers language-none"><code class="language-none">text=“abbc”
regex=“ab{1,3}c”<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>

<p>这个例子匹配目的是：匹配以 a 开头，以 c 结尾，中间有 1-3 个 b 字符的字符串。NFA 自动机对其解析的过程是这样的：</p>
<ul>
<li>读取正则表达式第一个匹配符 a 和字符串第一个字符 a 进行比较，a 对 a，匹配。</li>
<li>然后，读取正则表达式第二个匹配符 <code>b{1,3}</code> 和字符串的第二个字符 b 进行比较，匹配。但因为 <code>b{1,3}</code> 表示 1-3 个 b 字符串，NFA 自动机又具有贪婪特性，所以此时不会继续读取正则表达式的下一个匹配符，而是依旧使用 <code>b{1,3}</code> 和字符串的第三个字符 b 进行比较，结果还是匹配。</li>
<li>接着继续使用 <code>b{1,3}</code> 和字符串的第四个字符 c 进行比较，发现不匹配了，此时就会发生回溯，已经读取的字符串第四个字符 c 将被吐出去，指针回到第三个字符 b 的位置。</li>
<li>那么发生回溯以后，匹配过程怎么继续呢？程序会读取正则表达式的下一个匹配符 c，和字符串中的第四个字符 c 进行比较，结果匹配，结束。</li>
</ul>
<h3 id="如何避免回溯"><a href="#如何避免回溯" class="headerlink" title="如何避免回溯"></a>如何避免回溯</h3><h4 id="贪婪模式（Greedy）"><a href="#贪婪模式（Greedy）" class="headerlink" title="贪婪模式（Greedy）"></a>贪婪模式（Greedy）</h4><p>顾名思义，就是在数量匹配中，如果单独使用 +、 ? 、* 或{min,max} 等量词，正则表达式会匹配尽可能多的内容。</p>
<p>例如，上边那个例子：</p>
<pre class="line-numbers language-none"><code class="language-none">text=“abbc”
regex=“ab{1,3}c”<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>

<p>就是在贪婪模式下，NFA 自动机读取了最大的匹配范围，即匹配 3 个 b 字符。匹配发生了一次失败，就引起了一次回溯。如果匹配结果是“abbbc”，就会匹配成功。</p>
<pre class="line-numbers language-none"><code class="language-none">text=“abbbc”
regex=“ab{1,3}c”<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>

<h4 id="懒惰模式（Reluctant）"><a href="#懒惰模式（Reluctant）" class="headerlink" title="懒惰模式（Reluctant）"></a>懒惰模式（Reluctant）</h4><p>在该模式下，正则表达式会尽可能少地重复匹配字符。如果匹配成功，它会继续匹配剩余的字符串。</p>
<p>例如，在上面例子的字符后面加一个“？”，就可以开启懒惰模式。</p>
<pre class="line-numbers language-none"><code class="language-none">text=“abc”
regex=“ab{1,3}?c”<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>

<p>匹配结果是“abc”，该模式下 NFA 自动机首先选择最小的匹配范围，即匹配 1 个 b 字符，因此就避免了回溯问题。</p>
<h4 id="独占模式（Possessive）"><a href="#独占模式（Possessive）" class="headerlink" title="独占模式（Possessive）"></a>独占模式（Possessive）</h4><p>同贪婪模式一样，独占模式一样会最大限度地匹配更多内容；不同的是，在独占模式下，匹配失败就会结束匹配，不会发生回溯问题。</p>
<p>还是上边的例子，在字符后面加一个“+”，就可以开启独占模式。</p>
<pre class="line-numbers language-none"><code class="language-none">text=“abbc”
regex=“ab{1,3}+bc”<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>

<p>结果是不匹配，结束匹配，不会发生回溯问题。</p>
<blockquote>
<p>讲到这里，你应该非常清楚了，<strong>避免回溯的方法就是：使用懒惰模式和独占模式。</strong></p>
</blockquote>
<h3 id="正则表达式的优化"><a href="#正则表达式的优化" class="headerlink" title="正则表达式的优化"></a>正则表达式的优化</h3><h4 id="少用贪婪模式，多用独占模式"><a href="#少用贪婪模式，多用独占模式" class="headerlink" title="少用贪婪模式，多用独占模式"></a>少用贪婪模式，多用独占模式</h4><p>贪婪模式会引起回溯问题，可以使用独占模式来避免回溯。</p>
<h4 id="减少分支选择"><a href="#减少分支选择" class="headerlink" title="减少分支选择"></a>减少分支选择</h4><p>分支选择类型 <code>(X|Y|Z)</code> 的正则表达式会降低性能，我们在开发的时候要尽量减少使用。如果一定要用，我们可以通过以下几种方式来优化：</p>
<ul>
<li>首先，我们需要考虑选择的顺序，将比较常用的选择项放在前面，使它们可以较快地被匹配；</li>
<li>其次，我们可以尝试提取共用模式，例如，将 <code>(abcd|abef)</code> 替换为 <code>ab(cd|ef)</code>，后者匹配速度较快，因为 NFA 自动机会尝试匹配 ab，如果没有找到，就不会再尝试任何选项；</li>
<li>最后，如果是简单的分支选择类型，我们可以用三次 index 代替 <code>(X|Y|Z)</code>，如果测试的话，你就会发现三次 index 的效率要比 <code>(X|Y|Z)</code> 高出一些。</li>
</ul>
<h4 id="减少捕获嵌套"><a href="#减少捕获嵌套" class="headerlink" title="减少捕获嵌套"></a>减少捕获嵌套</h4><ul>
<li>捕获组是指把正则表达式中，子表达式匹配的内容保存到以数字编号或显式命名的数组中，方便后面引用。一般一个 () 就是一个捕获组，捕获组可以进行嵌套。</li>
<li>非捕获组则是指参与匹配却不进行分组编号的捕获组，其表达式一般由 <code>(?:exp)</code> 组成。</li>
</ul>
<p>在正则表达式中，每个捕获组都有一个编号，编号 0 代表整个匹配到的内容。我们可以看下面的例子：</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token class-name">String</span> text <span class="token operator">=</span> <span class="token string">"&lt;input high=\"20\" weight=\"70\"&gt;test&lt;/input&gt;"</span><span class="token punctuation">;</span>
	<span class="token class-name">String</span> reg<span class="token operator">=</span><span class="token string">"(&lt;input.*?&gt;)(.*?)(&lt;/input&gt;)"</span><span class="token punctuation">;</span>
	<span class="token class-name">Pattern</span> p <span class="token operator">=</span> <span class="token class-name">Pattern</span><span class="token punctuation">.</span><span class="token function">compile</span><span class="token punctuation">(</span>reg<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">Matcher</span> m <span class="token operator">=</span> p<span class="token punctuation">.</span><span class="token function">matcher</span><span class="token punctuation">(</span>text<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">while</span><span class="token punctuation">(</span>m<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>m<span class="token punctuation">.</span><span class="token function">group</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 整个匹配到的内容</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>m<span class="token punctuation">.</span><span class="token function">group</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//(&lt;input.*?&gt;)</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>m<span class="token punctuation">.</span><span class="token function">group</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//(.*?)</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>m<span class="token punctuation">.</span><span class="token function">group</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//(&lt;/input&gt;)</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>运行结果：</p>
<pre class="line-numbers language-none"><code class="language-none">&lt;input high=\"20\" weight=\"70\"&gt;test&lt;/input&gt;
&lt;input high=\"20\" weight=\"70\"&gt;
test
&lt;/input&gt;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre>

<p>如果你并不需要获取某一个分组内的文本，那么就使用非捕获分组。例如，使用“(?:X)”代替“(X)”，我们再看下面的例子：</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token class-name">String</span> text <span class="token operator">=</span> <span class="token string">"&lt;input high=\"20\" weight=\"70\"&gt;test&lt;/input&gt;"</span><span class="token punctuation">;</span>
	<span class="token class-name">String</span> reg<span class="token operator">=</span><span class="token string">"(?:&lt;input.*?&gt;)(.*?)(?:&lt;/input&gt;)"</span><span class="token punctuation">;</span>
	<span class="token class-name">Pattern</span> p <span class="token operator">=</span> <span class="token class-name">Pattern</span><span class="token punctuation">.</span><span class="token function">compile</span><span class="token punctuation">(</span>reg<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token class-name">Matcher</span> m <span class="token operator">=</span> p<span class="token punctuation">.</span><span class="token function">matcher</span><span class="token punctuation">(</span>text<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">while</span><span class="token punctuation">(</span>m<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>m<span class="token punctuation">.</span><span class="token function">group</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 整个匹配到的内容</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>m<span class="token punctuation">.</span><span class="token function">group</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//(.*?)</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>运行结果：</p>
<pre class="line-numbers language-none"><code class="language-none">&lt;input high=\"20\" weight=\"70\"&gt;test&lt;/input&gt;
test<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>

<p>综上可知：减少不需要获取的分组，可以提高正则表达式的性能。</p>
<h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul>
<li><a target="_blank" rel="noopener" href="http://deerchao.net/tutorials/regex/regex.htm">正则表达式 30 分钟入门教程</a></li>
<li><a target="_blank" rel="noopener" href="https://msdn.microsoft.com/zh-cn/library/d9eze55x(v=vs.80).aspx">msdn 正则表达式教程</a></li>
<li><a target="_blank" rel="noopener" href="http://blog.csdn.net/lxcnn/article/details/4362500">正则应用之——日期正则表达式</a></li>
<li><a target="_blank" rel="noopener" href="http://www.regexlib.com/">http://www.regexlib.com/</a></li>
<li><a target="_blank" rel="noopener" href="https://time.geekbang.org/column/intro/100028001">《Java 性能调优实战》</a></li>
</ul>

                
            </div>
            <hr/>

            

    <div class="reprint" id="reprint-statement">
        
            <div class="reprint__author">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-user">
                        文章作者:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="/blog/about" rel="external nofollow noreferrer">先谢郭嘉</a>
                </span>
            </div>
            <div class="reprint__type">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-link">
                        文章链接:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="https://xjb430.gitee.io/blog/2023/05/09/1683591981/">https://xjb430.gitee.io/blog/2023/05/09/1683591981/</a>
                </span>
            </div>
            <div class="reprint__notice">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-copyright">
                        版权声明:
                    </i>
                </span>
                <span class="reprint-info">
                    本博客所有文章除特別声明外，均采用
                    <a href="https://creativecommons.org/licenses/by/4.0/deed.zh" rel="external nofollow noreferrer" target="_blank">CC BY 4.0</a>
                    许可协议。转载请注明来源
                    <a href="/blog/about" target="_blank">先谢郭嘉</a>
                    !
                </span>
            </div>
        
    </div>

    <script async defer>
      document.addEventListener("copy", function (e) {
        let toastHTML = '<span>复制成功，请遵循本文的转载规则</span><button class="btn-flat toast-action" onclick="navToReprintStatement()" style="font-size: smaller">查看</a>';
        M.toast({html: toastHTML})
      });

      function navToReprintStatement() {
        $("html, body").animate({scrollTop: $("#reprint-statement").offset().top - 80}, 800);
      }
    </script>



            <div class="tag_share" style="display: block;">
                <div class="post-meta__tag-list" style="display: inline-block;">
                    
                        <div class="article-tag">
                            
                                <a href="/blog/tags/Java/">
                                    <span class="chip bg-color">Java</span>
                                </a>
                            
                                <a href="/blog/tags/JavaSE/">
                                    <span class="chip bg-color">JavaSE</span>
                                </a>
                            
                        </div>
                    
                </div>
                <div class="post_share" style="zoom: 80%; width: fit-content; display: inline-block; float: right; margin: -0.15rem 0;">
                    <link rel="stylesheet" type="text/css" href="/blog/libs/share/css/share.min.css">
<div id="article-share">

    
    <div class="social-share" data-sites="twitter,facebook,google,qq,qzone,wechat,weibo,douban,linkedin" data-wechat-qrcode-helper="<p>微信扫一扫即可分享！</p>"></div>
    <script src="/blog/libs/share/js/social-share.min.js"></script>
    

    

</div>

                </div>
            </div>
            
                <style>
    #reward {
        margin: 40px 0;
        text-align: center;
    }

    #reward .reward-link {
        font-size: 1.4rem;
        line-height: 38px;
    }

    #reward .btn-floating:hover {
        box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2), 0 5px 15px rgba(0, 0, 0, 0.2);
    }

    #rewardModal {
        width: 320px;
        height: 350px;
    }

    #rewardModal .reward-title {
        margin: 15px auto;
        padding-bottom: 5px;
    }

    #rewardModal .modal-content {
        padding: 10px;
    }

    #rewardModal .close {
        position: absolute;
        right: 15px;
        top: 15px;
        color: rgba(0, 0, 0, 0.5);
        font-size: 1.3rem;
        line-height: 20px;
        cursor: pointer;
    }

    #rewardModal .close:hover {
        color: #ef5350;
        transform: scale(1.3);
        -moz-transform:scale(1.3);
        -webkit-transform:scale(1.3);
        -o-transform:scale(1.3);
    }

    #rewardModal .reward-tabs {
        margin: 0 auto;
        width: 210px;
    }

    .reward-tabs .tabs {
        height: 38px;
        margin: 10px auto;
        padding-left: 0;
    }

    .reward-content ul {
        padding-left: 0 !important;
    }

    .reward-tabs .tabs .tab {
        height: 38px;
        line-height: 38px;
    }

    .reward-tabs .tab a {
        color: #fff;
        background-color: #ccc;
    }

    .reward-tabs .tab a:hover {
        background-color: #ccc;
        color: #fff;
    }

    .reward-tabs .wechat-tab .active {
        color: #fff !important;
        background-color: #22AB38 !important;
    }

    .reward-tabs .alipay-tab .active {
        color: #fff !important;
        background-color: #019FE8 !important;
    }

    .reward-tabs .reward-img {
        width: 210px;
        height: 210px;
    }
</style>

<div id="reward">
    <a href="#rewardModal" class="reward-link modal-trigger btn-floating btn-medium waves-effect waves-light red">赏</a>

    <!-- Modal Structure -->
    <div id="rewardModal" class="modal">
        <div class="modal-content">
            <a class="close modal-close"><i class="fas fa-times"></i></a>
            <h4 class="reward-title">你的赏识是我前进的动力</h4>
            <div class="reward-content">
                <div class="reward-tabs">
                    <ul class="tabs row">
                        <li class="tab col s6 alipay-tab waves-effect waves-light"><a href="#alipay">支付宝</a></li>
                        <li class="tab col s6 wechat-tab waves-effect waves-light"><a href="#wechat">微 信</a></li>
                    </ul>
                    <div id="alipay">
                        <img src="/blog/medias/reward/alipay.jpg" class="reward-img" alt="支付宝打赏二维码">
                    </div>
                    <div id="wechat">
                        <img src="/blog/medias/reward/wechat.png" class="reward-img" alt="微信打赏二维码">
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<script>
    $(function () {
        $('.tabs').tabs();
    });
</script>

            
        </div>
    </div>

    

    

    

    
    <div class="livere-card card" data-aos="fade-up">
    <!-- 来必力City版安装代码 -->
    <div id="lv-container" class="card-content" data-id="city" data-uid="MTAyMC81NTIwMS8zMTY2OA==">
        <script type="text/javascript">
            (function (d, s) {
                let j, e = d.getElementsByTagName(s)[0];
                if (typeof LivereTower === 'function') {
                    return;
                }

                j = d.createElement(s);
                j.src = 'https://cdn-city.livere.com/js/embed.dist.js';
                j.async = true;

                e.parentNode.insertBefore(j, e);
            })(document, 'script');
        </script>
        <noscript>为正常使用来必力评论功能请激活JavaScript。</noscript>
    </div>
    <!-- City版安装代码已完成 -->
</div>
    

    

    

    

    

    

<article id="prenext-posts" class="prev-next articles">
    <div class="row article-row">
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge left-badge text-color">
                <i class="fas fa-chevron-left"></i>&nbsp;上一篇</div>
            <div class="card">
                <a href="/blog/2023/05/09/1683595595/">
                    <div class="card-image">
                        
                        <img src="/blog/images/01-Java/01-JavaSE/background.jpg" class="responsive-img" alt="Java编码和加密">
                        
                        <span class="card-title">Java编码和加密</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            
                        
                    </div>
                    <div class="publish-info">
                        <span class="publish-date">
                            <i class="far fa-clock fa-fw icon-date"></i>2023-05-09
                        </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/blog/categorie/JavaSE/" class="post-category">
                                    JavaSE
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/blog/tags/Java/">
                        <span class="chip bg-color">Java</span>
                    </a>
                    
                    <a href="/blog/tags/JavaSE/">
                        <span class="chip bg-color">JavaSE</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge right-badge text-color">
                下一篇&nbsp;<i class="fas fa-chevron-right"></i>
            </div>
            <div class="card">
                <a href="/blog/2023/05/08/1683508280/">
                    <div class="card-image">
                        
                        <img src="/blog/images/01-Java/01-JavaSE/background.jpg" class="responsive-img" alt="Java注解">
                        
                        <span class="card-title">Java注解</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            
                        
                    </div>
                    <div class="publish-info">
                            <span class="publish-date">
                                <i class="far fa-clock fa-fw icon-date"></i>2023-05-08
                            </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/blog/categorie/JavaSE/" class="post-category">
                                    JavaSE
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/blog/tags/Java/">
                        <span class="chip bg-color">Java</span>
                    </a>
                    
                    <a href="/blog/tags/JavaSE/">
                        <span class="chip bg-color">JavaSE</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
    </div>
</article>

</div>


<script>
    $('#articleContent').on('copy', function (e) {
        // IE8 or earlier browser is 'undefined'
        if (typeof window.getSelection === 'undefined') return;

        var selection = window.getSelection();
        // if the selection is short let's not annoy our users.
        if (('' + selection).length < Number.parseInt('20')) {
            return;
        }

        // create a div outside of the visible area and fill it with the selected text.
        var bodyElement = document.getElementsByTagName('body')[0];
        var newdiv = document.createElement('div');
        newdiv.style.position = 'absolute';
        newdiv.style.left = '-99999px';
        bodyElement.appendChild(newdiv);
        newdiv.appendChild(selection.getRangeAt(0).cloneContents());

        // we need a <pre> tag workaround.
        // otherwise the text inside "pre" loses all the line breaks!
        if (selection.getRangeAt(0).commonAncestorContainer.nodeName === 'PRE' || selection.getRangeAt(0).commonAncestorContainer.nodeName === 'CODE') {
            newdiv.innerHTML = "<pre>" + newdiv.innerHTML + "</pre>";
        }

        var url = document.location.href;
        newdiv.innerHTML += '<br />'
            + '来源: 先谢郭嘉&#39;blog<br />'
            + '文章作者: 先谢郭嘉<br />'
            + '文章链接: <a href="' + url + '">' + url + '</a><br />'
            + '本文章著作权归作者所有，任何形式的转载都请注明出处。';

        selection.selectAllChildren(newdiv);
        window.setTimeout(function () {bodyElement.removeChild(newdiv);}, 200);
    });
</script>


<!-- 代码块功能依赖 -->
<script type="text/javascript" src="/blog/libs/codeBlock/codeBlockFuction.js"></script>

<!-- 代码语言 -->

<script type="text/javascript" src="/blog/libs/codeBlock/codeLang.js"></script>


<!-- 代码块复制 -->

<script type="text/javascript" src="/blog/libs/codeBlock/codeCopy.js"></script>


<!-- 代码块收缩 -->

<script type="text/javascript" src="/blog/libs/codeBlock/codeShrink.js"></script>


    </div>
    <div id="toc-aside" class="expanded col l3 hide-on-med-and-down">
        <div class="toc-widget card" style="background-color: white;">
            <div class="toc-title"><i class="far fa-list-alt"></i>&nbsp;&nbsp;目录</div>
            <div id="toc-content"></div>
        </div>
    </div>
</div>

<!-- TOC 悬浮按钮. -->

<div id="floating-toc-btn" class="hide-on-med-and-down">
    <a class="btn-floating btn-large bg-color">
        <i class="fas fa-list-ul"></i>
    </a>
</div>


<script src="/blog/libs/tocbot/tocbot.min.js"></script>
<script>
    $(function () {
        tocbot.init({
            tocSelector: '#toc-content',
            contentSelector: '#articleContent',
            headingsOffset: -($(window).height() * 0.4 - 45),
            collapseDepth: Number('0'),
            headingSelector: 'h1,h2, h3, h4'
        });

        // modify the toc link href to support Chinese.
        let i = 0;
        let tocHeading = 'toc-heading-';
        $('#toc-content a').each(function () {
            $(this).attr('href', '#' + tocHeading + (++i));
        });

        // modify the heading title id to support Chinese.
        i = 0;
        $('#articleContent').children('h1,h2, h3, h4').each(function () {
            $(this).attr('id', tocHeading + (++i));
        });

        // Set scroll toc fixed.
        let tocHeight = parseInt($(window).height() * 0.4 - 64);
        let $tocWidget = $('.toc-widget');
        $(window).scroll(function () {
            let scroll = $(window).scrollTop();
            /* add post toc fixed. */
            if (scroll > tocHeight) {
                $tocWidget.addClass('toc-fixed');
            } else {
                $tocWidget.removeClass('toc-fixed');
            }
        });

        
        /* 修复文章卡片 div 的宽度. */
        let fixPostCardWidth = function (srcId, targetId) {
            let srcDiv = $('#' + srcId);
            if (srcDiv.length === 0) {
                return;
            }

            let w = srcDiv.width();
            if (w >= 450) {
                w = w + 21;
            } else if (w >= 350 && w < 450) {
                w = w + 18;
            } else if (w >= 300 && w < 350) {
                w = w + 16;
            } else {
                w = w + 14;
            }
            $('#' + targetId).width(w);
        };

        // 切换TOC目录展开收缩的相关操作.
        const expandedClass = 'expanded';
        let $tocAside = $('#toc-aside');
        let $mainContent = $('#main-content');
        $('#floating-toc-btn .btn-floating').click(function () {
            if ($tocAside.hasClass(expandedClass)) {
                $tocAside.removeClass(expandedClass).hide();
                $mainContent.removeClass('l9');
            } else {
                $tocAside.addClass(expandedClass).show();
                $mainContent.addClass('l9');
            }
            fixPostCardWidth('artDetail', 'prenext-posts');
        });
        
    });
</script>

    

</main>




    <footer class="page-footer bg-color">
    
        <link rel="stylesheet" href="/blog/libs/aplayer/APlayer.min.css">
<style>
    .aplayer .aplayer-lrc p {
        
        display: none;
        
        font-size: 12px;
        font-weight: 700;
        line-height: 16px !important;
    }

    .aplayer .aplayer-lrc p.aplayer-lrc-current {
        
        display: none;
        
        font-size: 15px;
        color: #42b983;
    }

    
    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body {
        left: -66px !important;
    }

    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body:hover {
        left: 0px !important;
    }

    
</style>
<div class="">
    
    <div class="row">
        <meting-js class="col l8 offset-l2 m10 offset-m1 s12"
                   server="netease"
                   type="playlist"
                   id="503838841"
                   fixed='true'
                   autoplay='false'
                   theme='#42b983'
                   loop='all'
                   order='random'
                   preload='auto'
                   volume='0.7'
                   list-folded='true'
        >
        </meting-js>
    </div>
</div>

<script src="/blog/libs/aplayer/APlayer.min.js"></script>
<script src="/blog/libs/aplayer/Meting.min.js"></script>

    

    <div class="container row center-align"
         style="margin-bottom: 0px !important;">
        <div class="col s12 m8 l8 copy-right">
            Copyright&nbsp;&copy;
            
                <span id="year">2022-2023</span>
            
            <a href="/blog/about" target="_blank">先谢郭嘉</a>
            |&nbsp;Powered by&nbsp;<a href="https://hexo.io/" target="_blank">Hexo</a>
            |&nbsp;Theme&nbsp;<a href="https://github.com/blinkfox/hexo-theme-matery" target="_blank">Matery</a>
            <br>
            
                &nbsp;<i class="fas fa-chart-area"></i>&nbsp;站点总字数:&nbsp;<span
                        class="white-color">93.1k</span>
            
            
            
                
            
            
                <span id="busuanzi_container_site_pv">
                &nbsp;|&nbsp;<i class="far fa-eye"></i>&nbsp;总访问量:&nbsp;
                    <span id="busuanzi_value_site_pv" class="white-color"></span>
            </span>
            
            
                <span id="busuanzi_container_site_uv">
                &nbsp;|&nbsp;<i class="fas fa-users"></i>&nbsp;总访问人数:&nbsp;
                    <span id="busuanzi_value_site_uv" class="white-color"></span>
            </span>
            
            <br>

            <!-- 运行天数提醒. -->
            
            <br>
            
        </div>
        <div class="col s12 m4 l4 social-link social-statis">
    <a href="https://github.com/xiejiabin1" class="tooltipped" target="_blank" data-tooltip="访问我的GitHub" data-position="top" data-delay="50">
        <i class="fab fa-github"></i>
    </a>



    <a href="mailto:xie430423@163.com" class="tooltipped" target="_blank" data-tooltip="邮件联系我" data-position="top" data-delay="50">
        <i class="fas fa-envelope-open"></i>
    </a>







    <a href="tencent://AddContact/?fromId=50&fromSubId=1&subcmd=all&uin=2501267970" class="tooltipped" target="_blank" data-tooltip="QQ联系我: 2501267970" data-position="top" data-delay="50">
        <i class="fab fa-qq"></i>
    </a>







    <a href="/blog/atom.xml" class="tooltipped" target="_blank" data-tooltip="RSS 订阅" data-position="top" data-delay="50">
        <i class="fas fa-rss"></i>
    </a>

</div>
    </div>
</footer>

<div class="progress-bar"></div>


    <!-- 搜索遮罩框 -->
<div id="searchModal" class="modal">
    <div class="modal-content">
        <div class="search-header">
            <span class="title"><i class="fas fa-search"></i>&nbsp;&nbsp;搜索</span>
            <input type="search" id="searchInput" name="s" placeholder="请输入搜索的关键字"
                   class="search-input">
        </div>
        <div id="searchResult"></div>
    </div>
</div>

<script type="text/javascript">
$(function () {
    var searchFunc = function (path, search_id, content_id) {
        'use strict';
        $.ajax({
            url: path,
            dataType: "xml",
            success: function (xmlResponse) {
                // get the contents from search data
                var datas = $("entry", xmlResponse).map(function () {
                    return {
                        title: $("title", this).text(),
                        content: $("content", this).text(),
                        url: $("url", this).text()
                    };
                }).get();
                var $input = document.getElementById(search_id);
                var $resultContent = document.getElementById(content_id);
                $input.addEventListener('input', function () {
                    var str = '<ul class=\"search-result-list\">';
                    var keywords = this.value.trim().toLowerCase().split(/[\s\-]+/);
                    $resultContent.innerHTML = "";
                    if (this.value.trim().length <= 0) {
                        return;
                    }
                    // perform local searching
                    datas.forEach(function (data) {
                        var isMatch = true;
                        var data_title = data.title.trim().toLowerCase();
                        var data_content = data.content.trim().replace(/<[^>]+>/g, "").toLowerCase();
                        var data_url = data.url;
                        data_url = data_url.indexOf('/') === 0 ? data.url : '/' + data_url;
                        var index_title = -1;
                        var index_content = -1;
                        var first_occur = -1;
                        // only match artiles with not empty titles and contents
                        if (data_title !== '' && data_content !== '') {
                            keywords.forEach(function (keyword, i) {
                                index_title = data_title.indexOf(keyword);
                                index_content = data_content.indexOf(keyword);
                                if (index_title < 0 && index_content < 0) {
                                    isMatch = false;
                                } else {
                                    if (index_content < 0) {
                                        index_content = 0;
                                    }
                                    if (i === 0) {
                                        first_occur = index_content;
                                    }
                                }
                            });
                        }
                        // show search results
                        if (isMatch) {
                            str += "<li><a href='" + data_url + "' class='search-result-title'>" + data_title + "</a>";
                            var content = data.content.trim().replace(/<[^>]+>/g, "");
                            if (first_occur >= 0) {
                                // cut out 100 characters
                                var start = first_occur - 20;
                                var end = first_occur + 80;
                                if (start < 0) {
                                    start = 0;
                                }
                                if (start === 0) {
                                    end = 100;
                                }
                                if (end > content.length) {
                                    end = content.length;
                                }
                                var match_content = content.substr(start, end);
                                // highlight all keywords
                                keywords.forEach(function (keyword) {
                                    var regS = new RegExp(keyword, "gi");
                                    match_content = match_content.replace(regS, "<em class=\"search-keyword\">" + keyword + "</em>");
                                });

                                str += "<p class=\"search-result\">" + match_content + "...</p>"
                            }
                            str += "</li>";
                        }
                    });
                    str += "</ul>";
                    $resultContent.innerHTML = str;
                });
            }
        });
    };

    searchFunc('/blog/search.xml', 'searchInput', 'searchResult');
});
</script>

    <!-- 回到顶部按钮 -->
<div id="backTop" class="top-scroll">
    <a class="btn-floating btn-large waves-effect waves-light" href="#!">
        <i class="fas fa-arrow-up"></i>
    </a>
</div>


    <script src="/blog/libs/materialize/materialize.min.js"></script>
    <script src="/blog/libs/masonry/masonry.pkgd.min.js"></script>
    <script src="/blog/libs/aos/aos.js"></script>
    <script src="/blog/libs/scrollprogress/scrollProgress.min.js"></script>
    <script src="/blog/libs/lightGallery/js/lightgallery-all.min.js"></script>
    <script src="/blog/js/matery.js"></script>

    

    

    <!-- 雪花特效 -->
    

    <!-- 鼠标星星特效 -->
     
        <script type="text/javascript">
            // 只在桌面版网页启用特效
            var windowWidth = $(window).width();
            if (windowWidth > 768) {
                document.write('<script type="text/javascript" src="/blog/libs/others/star.js"><\/script>');
            }
        </script>
    

     
        <script src="https://ssl.captcha.qq.com/TCaptcha.js"></script>
        <script src="/blog/libs/others/TencentCaptcha.js"></script>
        <button id="TencentCaptcha" data-appid="0wmU-lR8LpCOiUEiFd1wmeQ**" data-cbfn="callback" type="button" hidden></button>
    

    <!-- Baidu Analytics -->

<script>
    var _hmt = _hmt || [];
    (function () {
        var hm = document.createElement("script");
        hm.src = "https://hm.baidu.com/hm.js?d163c694bac84954e606b3bd06e74597";
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(hm, s);
    })();
</script>


    <!-- Baidu Push -->

<script>
    (function () {
        var bp = document.createElement('script');
        var curProtocol = window.location.protocol.split(':')[0];
        if (curProtocol === 'https') {
            bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
        } else {
            bp.src = 'http://push.zhanzhang.baidu.com/push.js';
        }
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(bp, s);
    })();
</script>

    
    <script src="/blog/libs/others/clicklove.js" async="async"></script>
    
    
    <script async src="/blog/libs/others/busuanzi.pure.mini.js"></script>
    

    

    

    <!--腾讯兔小巢-->
    
    
    <script type="text/javascript" color="0,0,255"
        pointColor="0,0,255" opacity='0.7'
        zIndex="-1" count="99"
        src="/blog/libs/background/canvas-nest.js"></script>
    

    
    
    <script type="text/javascript" size="150" alpha='0.6'
        zIndex="-1" src="/blog/libs/background/ribbon-refresh.min.js" async="async"></script>
    

    
    <script type="text/javascript" src="/blog/libs/background/ribbon-dynamic.js" async="async"></script>
    

    
    <script src="/blog/libs/instantpage/instantpage.js" type="module"></script>
    

</body>

</html>
